i3a*_*non 35 .net c# lambda overloading overload-resolution
当我遇到这种特殊情况时,我正在实现同步/异步重载:
当我有一个没有参数或返回值的常规lambda表达式时,它会Run使用Action参数进行重载,这是可预测的.但是当lambda中有一个lambda时,while (true)它会通过Func参数进入重载状态.
public void Test()
{
Run(() => { var name = "bar"; });
Run(() => { while (true) ; });
}
void Run(Action action)
{
Console.WriteLine("action");
}
void Run(Func<Task> func) // Same behavior with Func<T> of any type.
{
Console.WriteLine("func");
}
Run Code Online (Sandbox Code Playgroud)
输出:
动作
功能
那怎么可能呢?有原因吗?
Ser*_*rvy 26
首先,第一个表达式只能调用第一个重载.它不是a的有效表达式,Func<Task>因为存在返回无效值(void而不是Task)的代码路径.
() => while(true)实际上是任一签名的有效方法.(它,连同实现,比如() => throw new Expression();是返回任何可能的类型,包括方法的有效机构void,琐事的一个有趣的问题,为什么自动生成的方法,从一个IDE通常只是抛出一个异常,它会不顾编译的签名是无限循环的方法.)的方法是,其中有没有代码路径不返回正确的值(和"正确的价值"是否是这是真的的方法void,Task或从字面上别的).这当然是因为它永远不会返回值,并且它以编译器可以证明的方式执行.(如果它以编译器无法证明的方式这样做,因为它毕竟没有解决停止问题,那么我们将在同一条船上A.)
因此,对于我们的无限循环,这是更好的,因为两个过载都适用.这将我们带到了C#规范的更好部分.
如果我们转到第7.4.3.3节,第4章,我们看到:
如果E是匿名函数,T1和T2是委托类型或表达式树类型的具有相同的参数列表,并且推断的返回类型X在于参数列表(§7.4.2.11)的上下文中存在E:
[...]
如果T1的返回类型为Y,并且T2返回为空,那么C1是更好的转换.
因此,当从匿名委托进行转换时,这就是我们正在做的事情,它将更喜欢转换返回值的转换void,因此它选择Func<Task>.
| 归档时间: |
|
| 查看次数: |
830 次 |
| 最近记录: |