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

时间:2019-03-17 12:25:01

标签: c# out null-coalescing

使用此构造:

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

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

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

2 个答案:

答案 0 :(得分:10)

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

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

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

  • 局部变量value仅在dict不为null的情况下才被明确分配,因此在达到结果后{em>不确定地分配value

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

  • 所以这是一个错误。

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

顺便说一句,C#2.0编译器太聪明了。例如,如果您对某个int本地0 * x == 0具有类似x的条件,则它将得出“无论x的值是什么,该条件始终为真”并标记出替代分支由于无法到达。从与现实世界相匹配的意义上说,这种分析是正确的,但从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");

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

答案 1 :(得分:4)

  

仅仅是编译器无法完全评估该语句吗?

是,或多或少。

编译器不会跟踪未分配的,而是跟踪相反的“明确分配的”。它必须停在某处,在这种情况下,它需要合并有关库方法library(data.table) setDT(df)[order(Timestamp), .SD[!duplicated(rleid(Text), fromLast = TRUE)]] Timestamp Text 1: 2018-01-08 13:45:12 A 2: 2018-01-08 14:26:22 B 3: 2018-01-08 14:31:32 C 4: 2018-01-08 15:13:16 A 5: 2018-01-08 15:25:19 B 的知识。没有。