Is it possible to force a task to execute synchronously, on the current thread?
That is, is it possible, by e.g. passing some parameter to StartNew()
, to make this code:
Task.Factory.StartNew(() => ThisShouldBeExecutedSynchronously());
behave like this:
ThisShouldBeExecutedSynchronously();
Background:
I have an interface called IThreads
:
public interface IThreads
{
Task<TRet> StartNew<TRet>(Func<TRet> func);
}
I would like to have two implemenetations of this, one normal that uses threads:
public class Threads : IThreads
{
public Task<TRet> StartNew<TRet>(Func<TRet> func)
{
return Task.Factory.StartNew(func);
}
}
And one that does not use threads (used in some testing scenarios):
public class NoThreading : IThreads
{
public Task<TRet> StartNew<TRet>(Func<TRet> func)
{
// What do I write here?
}
}
I could let the NoThreading
version just call func()
, but I want to return an instance of Task<TRet>
on which I can perform operations such as ContinueWith()
.
Since you mention testing, you might prefer using a
TaskCompletionSource<T>
since it also lets you set an exception or set the task as cancelled (works in .Net 4 and 4.5):Return a completed task with a result:
Return a faulted task:
Return a canceled task:
You can simply return the result of
func()
wrapped in aTask
.Now you can attach "continue with" tasks to this.
Task scheduler decides whether to run a task on a new thread or on the current thread. There is an option to force running it on a new thread, but none forcing it to run on the current thread.
But there is a method
Task.RunSynchronously()
whichMore on MSDN.
Also if you are using
async/await
there is already a similar question on that.OP here. This is my final solution (which actually solves a lot more than I asked about).
I use the same implementation for
Threads
in both test and production, but pass in differentTaskSchedulers
:I wrap the
Task
in aTaskContinuation
class in order to be able to specifyTaskScheduler
for theContinueWith()
call.I create my custom
TaskScheduler
that dispatches the action on the thread that scheduler was created on:Now I can specify the behaviour by passing in different
TaskSchedulers
to theThreads
constructor.Finally, since the event loop doesn't run automatically in my unit test, I have to execute it manually. Whenever I need to wait for a background operation to complete I execute the following (from the main thread):
The
DispatcherHelper
can be found here.Yes, you can pretty much do that using custom task schedulers.