![](/img/trans.png)
[英]T of Func<S, T> is inferred from output of lambda expression only when S and T are different?
[英]Lambda of “x => { throw .. }” inferred to match Func<T,Task> in overloaded method?
我不明白为什么C#最终在以下LINQPad代码中执行不正确的扩展方法:
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?
我希望在第三次调用Run()时看到“Actual:Sync Action”,因为lambda中没有任何内容表明这是一个Func返回Task。
这只是一个重载解决问题。 显然,lambda x => { throw new Exception("Meh"); }
x => { throw new Exception("Meh"); }
可以被转化到任何一个Action<T>
或一个Func<T, SomeNonVoidType>
以及许多其他委托类型无关这个问题)。 这只是C#的重载决策规则,在这种情况下更喜欢后者。
这是一个更具代表性的例子:
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();
}
}
至于为什么会出现这种情况,我不是百分百肯定,但随便看一下这个规格就会向我展示下面可能的解释(强调我的):
7.5.3过载分辨率
[...]
7.5.3.3更好地从表达转换
给定从表达式E转换为类型T1的隐式转换C1,以及从表达式E转换为类型T2的隐式转换C2,如果以下至少一个成立,则C1是比C2更好的转换:
[...]
•E是匿名函数,T1是委托类型D1或表达式树类型
Expression<D1>
,T2是委托类型D2或表达式树类型Expression<D2>
并且以下之一成立:[...]
•D1的返回类型为Y,D2返回无效
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.