Explicitly use a Func<Task> for asynchronous lambda function when Action overload is available
Because
Task.Run
has signatures of bothTask.Run(Func<Task>)
andTask.Run(Action)
, what type is the async anonymous function compiled to? Anasync void
or aFunc<Task>
? My gut feeling says it will compile down to anasync void
purely because its a non-generic type however the C# Compiler might be smart and giveFunc<Task>
types preference.
The general rule, even without async
, is that a delegate with a return type is a better match than a delegate without a return type. Another example of this is:
static void Foo(Action a) { }
static void Foo(Func<int> f) { }
static void Bar()
{
Foo(() => { throw new Exception(); });
}
This is unambiguous and calls the second overload of Foo
.
Also, is there a way to explicitly declare which overload I wish to use?
A nice way to make this clear is to specify the parameter name. The parameter names for the Action
and Func<Task>
overloads are different.
Task.Run(action: async () => {
await Task.Delay(1000);
});
Task.Run(function: async () => {
await Task.Delay(1000);
});
I just checked it gets compiled into Task.Run(Func<Task>)
by default, I don't have good explanation for this.
Here is the relevant part of IL
IL_0001: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0006: brtrue.s IL_001B
IL_0008: ldnull
IL_0009: ldftn UserQuery.<Main>b__0
IL_000F: newobj System.Func<System.Threading.Tasks.Task>..ctor//<--Note here
IL_0014: stsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0019: br.s IL_001B
IL_001B: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0020: call System.Threading.Tasks.Task.Run
you can check this easily using visual studio type inference, it will show you what method it will be compiled if you just place mouse over the method, or just click the method press F12 you can see the metadata which will tell you what was the type inferred by compiler.
Also, is there a way to explicitly declare which overload I wish to use? Yes, Specify the delegate explicitly.
Task.Run(new Action(async () =>
{
await Task.Delay(1000);
}));
Task.Run(new Func<Task>(async () =>
{
await Task.Delay(1000);
}));