I have some GUI on a bunch of LINQ queries. The queries take some time to execute, so I would like for the GUI to be responsive and show busyindicators and progress bars. Many of the queries are to check for certain conditions existing in the data. If the query returns an empty result, the app shall continue with the next query. If it returns a result, the return set will either be of severity "warnings" or "errors". If it is warnings, execution shall continue. If it is errors, it shall stop.
Much code plays "ping pong" with the threadpool and GUI. Quasi code:
TaskFactory.StartNew(()=>
{
Run in background
}.ContinueInGui(()=>
{
Update something
}).ContinueInBackground(()=>
{
Do more work;
}).ContinueInGui(()=> etc etc
This is tidy and nice. However, I don't see how I can insert conditions to go different continuation routes or break off the continuation chain if errors are found in the data.
There is no method for ContinueWithIf( predicate ,delegate{},TaskScheduler) Do I use TaskCancellation, do I throw an exception? Or is there some simple branching mechanism that I'm not thinking of?
ContinueWith(Action<Task,Object>, Object, TaskScheduler)Creates a continuation that receives caller-supplied state information and executes asynchronously when the target Task completes.
The ContinueWith function is a method available on the task that allows executing code after the task has finished execution. In simple words it allows continuation. Things to note here is that ContinueWith also returns one Task. That means you can attach ContinueWith one task returned by this method.
To start a task in C#, follow any of the below given ways. Use a delegate to start a task. Task t = new Task(delegate { PrintMessage(); }); t. Start();
A good option here would be to use a CancelationTokenSource
, and just mark it canceled if you want to "break" your continuation chain. By including TaskContinuationOptions.NotOnCanceled in the ContinueWith
for subsequent tasks, you can have them not get scheduled at any point by marking a CancelationTokenSource
as canceled.
If you really want to use a predicate, instead of setting up the continuation in the main method, you'd need to make a custom method to handle this for you. This can be done by having an extension method that attaches a continuation - that continuation can check the predicate, and fire off the continuation if appropriate. This would look something like:
public static Task ContinueWithIf(this Task task, Func<bool> predicate, Action<Task> continuation, TaskScheduler scheduler)
{
var tcs = new TaskCompletionSource<object>();
task.ContinueWith( t =>
{
if (predicate())
{
new TaskFactory(scheduler).StartNew(
() =>
{
continuation(task);
tcs.SetResult(null);
});
}
else
{
tcs.TrySetCanceled();
}
});
return tcs.Task;
}
Granted, you'd probably want to make a version for Task<T>
in addition, as well as handle the faulted/canceled states on the Task. That being said, it should function correctly.
If there are errors, you should consider making your task fault accordingly. Then you can use TaskContinuationOptions.OnlyOnRanToCompletion
etc in the ContinueWith
call.
Basically there are three possible states at the end of a task's life:
You can make ContinueWith
apply to any sensible combination of those statuses, and you can attach different continuations to the same parent task if you want to do different things based on error vs success vs cancellation etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With