c# - 带有 while (true) 的特殊重载决议

标签 c# .net lambda overloading overload-resolution

当我遇到这种特殊情况时,我正在实现同步/异步重载:

当我有一个没有参数或返回值的常规 lambda 表达式时,它会转到带有 Action 参数的 Run 重载,这是可以预测的。但是,当该 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");
}

输出:

action
func

那怎么可能呢?有什么理由吗?

最佳答案

所以首先,第一个表达式只能调用第一个重载。它不是 Func<Task> 的有效表达式,因为存在返回无效值的代码路径(void 而不是 Task)。

() => while(true) 实际上是任一签名的有效方法。 (它与 () => throw new Expression(); 等实现一起是返回任何可能类型的有效方法体,包括 void ,这是一个有趣的琐事点,以及为什么从 IDE 自动生成的方法通常只抛出异常;无论方法的签名。)无限循环的方法是其中没有不返回正确值的代码路径的方法(无论“正确值”是 voidTask 还是其他任何字面意思都是如此)。这当然是因为它从不 返回一个值,而且它以编译器可以证明的方式返回。 (如果它以编译器无法证明的方式这样做,因为它毕竟没有解决停止问题,那么我们将与 A 在同一条船上。)

因此,对于我们的无限循环,考虑到两个重载都适用,哪个更好。这将我们带到了 C# 规范的优势部分。

如果我们转到第 7.4.3.3 节的第 4 点,我们会看到:

If E is an anonymous function, T1 and T2 are delegate types or expression tree types with identical parameter lists, and an inferred return type X exists for E in the context of that parameter list (§7.4.2.11):

[...]

if T1 has a return type Y, and T2 is void returning, then C1 is the better conversion.

因此,当从匿名委托(delegate)转换时,这就是我们正在做的事情,它会更喜欢返回值的转换,而不是 void ,因此它选择 Func<Task>

关于c# - 带有 while (true) 的特殊重载决议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36137960/

相关文章:

c# - 在用 C++ 编写的 COM 客户端中抛出空返回值异常

python - 列表中的 lambda 函数如何工作 : Python?

c++ - VS2010 中不同大小的 lambda 表达式?

c# - 从 View 按钮调用 Mvc Controller 方法

c# - 依赖注入(inject)和第三方 API - 带 PI 的扩展方法或带 CI 的包装器

c# - ASP.NET 4 自定义成员资格提供程序表

.net - 是否有可以将 PNG 文件转换为 PDF 的 .NET 库?

.net - 关闭读取器时,处置数据上下文会导致调用 Read 的尝试无效

c# - 如何提高 .Net 中的 JSON 反序列化速度? (JSON.net 还是其他?)

c++ - 将对临时/匿名 lambda 的 const 引用传递给 std::thread 构造函数是否安全?