tags:

views:

136

answers:

3

I'm attempting to programmatically chain asynchronous operations in C#4, such as Writes to a given Stream object. I originally did this "manually", hooking callbacks from one operation to the next, but I thought I'd try the .NET 4 Task Parallel Library to save myself the trouble of re-inventing the concurrent wheel.

To start with, I wrap my async calls in Tasks like so:

public static Task CreateWriteTask(Stream stream, byte[] data)
{
    return Task.Factory.FromAsync(stream.BeginWrite, stream.EndWrite, data, 0, data.Length, null);
}

Continuations have made chaining synchronous operations very easy (if you'll excuse the unfortunate method name):

public static Task ChainFlush(Stream stream, Task precedingTask)
{
    return precedingTask.ContinueWith(x => stream.Flush());
}

But there is no version of the Task.ContinueWith method that accepts an async operation in the same way as TaskFactory.FromAsync.

So, assuming that I persist with using the TPL, what I'm looking for the correct implementation of this method:

public static Task ChainWrite(Stream stream, byte[] data, Task precedingTask)
{
    //?
}
+2  A: 

My best idea so far is to chain the creation of the new write task, then use the Unwrap extension method to turn Task<Task> back into Task:

public static Task ChainWrite(Stream stream, byte[] data, Task precedingTask)
{
    return precedingTask.ContinueWith(x => CreateWriteTask(stream, data)).Unwrap();
}
FacticiusVir
+1  A: 

Please try ContinueWhenAll, ContinueWhenAny instead of ContinueWith.

Links to refer:

*This is my first post. So please ignore my n00b errors.

Here is MSDN link: - http://msdn.microsoft.com/en-us/library/dd997423.aspx
Interesting references, but doesn't actually solve my problem. ContinueWhenAll/Any don't have overloads for accepting Async Ops, just Action<Task> and Func<Task, T>. The Iterator implementation in your link is an interesting idea and I may adapt that for another issue I've come up against, but it assumes that I'm doing that same thing over and over, and is basically an iterative way of doing what I'd mentioned in my existing answer (creating a task inside another task). Thanks anyway!
FacticiusVir
A: 

As far as I understand it, this is an unfortunate consequence of not being in control over when a task gets started. Since you never know when a task gets started, there can't be an overload like

precedingTask.ContinueWith(Task nextTask)

because once created, it might already be started when you get to 'ContinueWith'. Besides, it would also make a mess of types. What should be the type here:

precedingTask<T>.ContinueWith(Task<..what?..> nextTask)

preceding returns a T, so next takes what and returns what? :) This could be solved with closures though.

Robert Jeppesen