"x =>"的λ {throw ..}"推断为匹配Func< T,Task>在重载方法? [英] Lambda of "x => { throw .. }" inferred to match Func<T,Task> in overloaded method?
问题描述
我不明白为什么C#最终在以下LINQPad代码中执行了错误的扩展方法:
I don't understand why C# ends up executing an incorrect extension method in the following LINQPad code:
void Main()
{
// Actual: Sync Action
"Expected: Sync Action".Run(x => { x.Dump(); });
// Actual: Async Task
"Expected: Async Task".Run(async x => { await System.Threading.Tasks.Task.Run(() => x.Dump()); });
// Actual: Async Task!!
"Expected: Sync Action".Run(x => { throw new Exception("Meh"); });
}
static class Extensions
{
public static void Run<T>(this T instance, Action<T> action)
{
"Actual: Sync Action".Dump();
action(instance);
}
public static void Run<T>(this T instance, Func<T, System.Threading.Tasks.Task> func)
{
"Actual: Async Task".Dump();
func(instance).Wait();
}
}
为什么编译器认为lambda在这里返回一个Task?
Why does the compiler think that the lambda returns a Task here?
我希望在Run()的第三次调用中看到"Actual:Sync Action",因为lambda中没有任何内容表明这是一个返回Func的Task.
I expected to see "Actual: Sync Action" in the third call to Run() since nothing in the lambda indicates that this is a Func returning Task.
推荐答案
这只是一个超载解决问题.显然,lambda x => { throw new Exception("Meh"); }
可以转换为Action<T>
或Func<T, SomeNonVoidType>
(以及与该问题无关的许多其他委托类型).在这种情况下,仅C#的重载解析规则更喜欢后者.
This is simply an overload resolution issue. Clearly, the lambda x => { throw new Exception("Meh"); }
can be converted to either an Action<T>
or to a Func<T, SomeNonVoidType>
(as well as to many other delegate types irrelevant to this question). It's simply C#'s overload resolution rules that prefer the latter in this case.
这是一个更具代表性的示例:
Here's a more representative example:
void Main()
{
// Output: Func<T, int>
"Test".WhatsThis(x => { throw new Exception("Meh"); });
}
static class Extensions
{
public static void WhatsThis<T>(this T dummy, Action<T> action)
{
"Action<T>".Dump();
}
public static void WhatsThis<T>(this T dummy, Func<T, int> func)
{
"Func<T, int>".Dump();
}
}
As for why this is the case, I'm not 100% sure, but a casual look at the spec shows me the below likely explanation (emphasis mine):
7.5.3重载分辨率
7.5.3 Overload resolution
[...]
7.5.3.3从表达式更好的转换
7.5.3.3 Better conversion from expression
鉴于从表达式E转换为类型T1的隐式转换C1和从表达式E转换为类型T2的隐式转换C2,如果满足以下至少一项条件,则C1比C2更好. :
Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that converts from an expression E to a type T2, C1 is a better conversion than C2 if at least one of the following holds:
[...]
•E是一个匿名函数,T1是委托类型D1或表达式树类型
Expression<D1>
,T2是委托类型D2或表达式树
键入Expression<D2>
并保留以下内容之一:
• E is an anonymous function, T1 is either a delegate type D1 or an expression tree type
Expression<D1>
, T2 is either a delegate type D2 or an expression tree
type Expression<D2>
and one of the following holds:
[...]
•D1的返回类型为Y,而D2返回的返回类型为空
这篇关于"x =>"的λ {throw ..}"推断为匹配Func< T,Task>在重载方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!