使用此构造:
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
。
我在这里想念什么?只是编译器无法完全评估该语句吗?还是我以某种方式搞砸了?
答案 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
的知识。没有。