Reputation: 144
I wrote a function that will, using the relatively new async/await pattern run any function on a thread and notify the caller later via an optional callback method. The function is super simple and looks like this:
private async void DoOperationAsync<T>(Func<T> operation, Action<T> resultAction = null)
{
if (operation == null)
throw new ArgumentNullException("operation");
var result = await Task<T>.Factory.StartNew(operation);
// Notify someone that this finished
if (resultAction != null)
resultAction(result);
}
This works very well for functions that return a value. It doesn't work for is functions that return void (Or maybe I'm not smart enough to make it work). I could write a special case of this method that doesn't assume a return type. However, I wonder if some C# generics gurus could point out a way to handle void in this case. Is there are way for that to work that doesn't involve a special case for void functions?
Upvotes: 1
Views: 1174
Reputation: 10741
You should avoid wrapping Task<T>.Factory.StartNew
. Use it directly instead, and favour Task.Run
over it where possible, as @StephenCleary advises in his answer.
Nevertheless, I think your question still makes sense for some other patterns. If you do not want to implement generic and non-generic versions of the method, you can use fake Empty
struct as generic parameter. For example, there is TaskCompletionSource<T>
class and Task.FromResult<T>
method type in TPL, they do not have non-generic versions. If you do not want to leak the information, the code may look similar to this:
public struct Empty {
public static Empty Value {
get { return default(Empty); }
}
static Task GetCompletedTask() {
return Task.FromResult(Empty.Value); }
You can turn any void
method into Empty
func:
static Func<Empty> Func(Action action) {
return () => { action(); return Empty.Value; };
}
DoOperationAsync(Func(() =>
Console.WriteLine("Hello, World!")));
This can make it work with your existing generic method, without leaking any result to the caller.
Upvotes: 0
Reputation: 457422
I have an async
/await
intro on my blog that you may find helpful.
I wrote a function that will, using the relatively new async/await pattern run any function on a thread and notify the caller later via an optional callback method.
That's what Task.Run
is for.
I do want that method to run on the calling thread (in my case, it will be the main UI thread of my application in general).
And await
already does that.
So, instead of writing code like this:
DoOperationAsync(() =>
{
// Code that runs on threadpool thread.
return 13;
},
result =>
{
// Code that runs on UI thread.
MessageBox.Show(result.ToString());
});
Just do this:
var result = await Task.Run(() =>
{
// Code that runs on threadpool thread.
return 13;
});
// Code that runs on UI thread.
MessageBox.Show(result.ToString());
P.S. Task.Run
already has all the necessary overloads for handling delegates with and without return values.
Upvotes: 5
Reputation: 467
Try having a non generic version of the method which awaits a non generic task before executing the callback
private async void DoOperationAsync(Func operation, Action resultAction = null)
{
if (operation == null)
throw new ArgumentNullException("operation");
await Task.Factory.StartNew(operation);
// Notify someone that this finished
if (resultAction != null)
resultAction();
}
Upvotes: 0