Null-coalescing out参数给出意外警告

Jak*_*lås 6 c# out null-coalescing

使用此构造:

var dict = new Dictionary<int, string>();
var result = (dict?.TryGetValue(1, out var value) ?? false) ? value : "Default";
Run Code Online (Sandbox Code Playgroud)

我收到一个错误消息,说CS0165 use of unassigned local variable 'value'那不是我期望的。怎么value可能不确定?如果字典为null,则将返回内部语句false,这将使外部语句的值为false,返回Default

我在这里想念什么?只是编译器无法完全评估该语句吗?还是我搞砸了?

Eri*_*ert 10

您的分析是正确的。这不是编译器进行的分析,因为编译器进行C#规范要求的分析。该分析如下:

  • 如果condition?consequence:alternative表达式的条件是编译时常量,true则备用分支将无法访问;如果false,则结果分支不可达;否则,两个分支都是可以到达的。

  • 在这种情况下,条件不是恒定的,因此结果和替代方法都是可以实现的。

  • 局部变量value,如果只分配绝对dict不为空,因此value不明确赋值达到结果的时候。

  • 但后果是value必须明确分配

  • 所以这是一个错误。

编译器不如您聪明,但是它是C#规范的准确实现。(请注意,我没有在此处勾画出这种情况的其他特殊规则,其中包括谓词,例如“在真表达式后确定赋值”,等等。有关详细信息,请参见C#规范。)

顺便说一句,C#2.0编译器太聪明了。例如,如果您有类似0 * x == 0int local 的条件x,它将得出“无论xis 的值如何,该条件始终为真”,并将替代分支标记为不可访问。从与现实世界相匹配的意义上说,这种分析是正确的,但从C#规范中明确指出仅对编译时常进行推论,并同样明确地指出,涉及变量的表达式是不是恒定的

记住,这件事的目的是发现错误,更可能是什么?有人写0 * x == 0 ? foo : bar它的意图是“总是foo”,还是偶然写了一个bug?我修复了编译器中的错误,此后此错误已严格符合规范。

在您的情况下,没有错误,但是代码太复杂而无法编译器进行分析,因此可能也太过复杂以至于无法让人进行分析。看看是否可以简化它。我可能会做的是:

public static V GetValueOrDefault<K, V>(
  this Dictionary<K, V> d,
  K key,
  V defaultValue)
{
    if (d != null && d.TryGetValue(key, out var value))
      return value;
    return defaultValue;
}
…
var result = dict.GetValueOrDefault(1, "Default");
Run Code Online (Sandbox Code Playgroud)

目标应该是使呼叫站点可读;我认为我的呼叫站点比您的站点更具可读性。


Hen*_*man 5

难道只是编译器无法完全评估该语句吗?

是的,或多或少。

编译器不跟踪未分配的情况,它跟踪相反的“明确分配的”。它必须在某个地方停下来,在这种情况下,它需要结合有关库方法的知识TryGetValue()。事实并非如此。

  • 是的,我认为 @PetSerAl 更接近于未考虑的“?.”和“??”运算符。 (2认同)