I\'ve got the following scenario, which I think might be quite common:
There is a task (a UI command handler) which can complete either synchronously or asy
I almost forgot it's possible to construct a Task
manually, without starting or scheduling it. Then, "Task.Factory.StartNew" vs "new Task(...).Start" put me back on track. I think this is one of those few cases when the TaskTask
) and Task.Unwrap():
// AsyncOp
class AsyncOp
{
Task _pending = Task.FromResult(default(T));
public Task CurrentTask { get { return _pending; } }
public Task RunAsync(Func> handler, bool useSynchronizationContext = false)
{
var pending = _pending;
Func> wrapper = async () =>
{
// await the prev task
var prevResult = await pending;
Console.WriteLine("\nprev task result: " + prevResult);
// start and await the handler
return await handler();
};
var task = new Task>(wrapper);
var inner = task.Unwrap();
_pending = inner;
task.RunSynchronously(useSynchronizationContext ?
TaskScheduler.FromCurrentSynchronizationContext() :
TaskScheduler.Current);
return inner;
}
}
The output:
Test #1... prev task result: 0 this task arg: 1000 prev task result: 1000 this task arg: 900 prev task result: 900 this task arg: 800 Press any key to continue to test #2... prev task result: 800 this task arg: 100 prev task result: 100 this task arg: 200
It's now also very easy to make AsyncOp
thread-safe by adding a lock
to protect _pending
, if needed.
Updated, this has been further improved with cancel/restart logic.