带有 while (true) 的特殊重载解决方案

Posted

技术标签:

【中文标题】带有 while (true) 的特殊重载解决方案【英文标题】:Peculiar overload resolution with while (true) 【发布时间】:2014-08-10 13:22:52 【问题描述】:

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

当我有一个不带参数或返回值的常规 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");

输出:

动作 函数

那么,怎么可能呢?有什么原因吗?

【问题讨论】:

有趣。看起来你对任何 Func&lt;T&gt; 类型也有相同的行为。我尝试了Func&lt;int&gt;Func&lt;string&gt;,结果相同。 @L.B 他在询问重载解决方案。他意识到他没有给代表打电话。 奇数。将其更改为while (false) ;,它被视为Action 摆脱重载解决方案。这个问题可以简化为是什么让Func&lt;Any T&gt; func = () =&gt; while(true) ; ; 编译。 @AnthonyPegram:不,重载解决方案很重要。如果你取出 Func 重载它仍然可以编译(打印“action” x 2),但如果你取出 Action 一个它不会。所以有一些东西使无限循环更喜欢Func重载而不是Action 【参考方案1】:

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

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

所以,对于我们的无限循环,这更好,因为这两个重载都适用。这将我们带到 C# 规范的更好部分。

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

如果 E 是匿名函数,则 T1 和 T2 是具有相同参数列表的委托类型或表达式树类型,并且在该参数列表的上下文中存在 E 的推断返回类型 X(第 7.4.2.11 节):

[...]

如果 T1 有一个返回类型 Y,而 T2 是 void 返回,那么 C1 是更好的转换。

因此,当我们正在从匿名委托进行转换时,它会更喜欢返回值的转换而不是 void,因此它选择 Func&lt;Task&gt;

【讨论】:

+1,就是这样。我刚回到这里阅读了 C# 4.0 规范的等效第 7.5.3.3 节(你引用哪个版本?)。荣誉。 @Jon 我认为是 3.0,因为它是我首先在我的电脑上找到的。 @I3arnon 你必须问问做出决定的人为什么做出决定。 @I3arnon:做出决定的人是一个相当大的群体,但执行该决定的人是我。原因是:如果您有 ()=&gt;X() 其中 X() 返回一个值,那么您打算使用该值的可能性很大;如果你打算忽略它,你会写()=&gt;X();。因此,如果在“使用价值”和“忽略价值”之间进行选择,我们选择“使用价值”——在不明确的情况下,我们选择 Func 而不是 Action @RoyiNamir 这不是代码路径,因为它不会导致离开方法。方法中没有代码路径,因为没有代码离开方法的地方。

以上是关于带有 while (true) 的特殊重载解决方案的主要内容,如果未能解决你的问题,请参考以下文章

函数重载以及二义性

带有“if”的while循环无法正常工作

While 循环计时如何在带有多个线程的 C# 中工作?

带有替代方法的重载方法值选择

带有双条件和 || 的 While 循环Swift 中的逻辑运算符

3-4特殊的流程控制语句