【发布时间】:2025-12-05 10:35:02
【问题描述】:
假设我有一个类,其属性类型为Dictionary<string,string>,它可能为空。
这可以编译,但对 TryGetValue() 的调用可能会在运行时引发 NullRef 异常:
MyClass c = ...;
string val;
if(c.PossiblyNullDictionary.TryGetValue("someKey", out val)) {
Console.WriteLine(val);
}
所以我添加了一个空传播运算符来防止空值,但这不会编译:
MyClass c = ...;
string val;
if( c.PossiblyNullDictionary ?. TryGetValue("someKey", out val) ?? false ) {
Console.WriteLine(val); // use of unassigned local variable
}
是否存在val 在if 块内未初始化的实际用例,或者编译器不能简单地推断出这一点(以及为什么)?
更新:最干净的 (?) 解决方法^H^H^H^H^H 解决这个问题是:
MyClass c = ...;
string val = null; //POW! initialized.
if( c.PossiblyNullDictionary ?. TryGetValue("someKey", out val) ?? false ) {
Console.WriteLine(val); // no more compiler error
}
【问题讨论】:
-
编译器 prolly 不关心/不知道 TryGetValue 结果的语义。它只关心调用它会初始化 val。如果 TryGetValue 根本没有被调用,你就不能认为它已正确初始化。
-
@user6144226 只要 TryGetValue 运行,它返回什么都没关系。 C# 规范强制任何采用
out参数的方法在返回之前对其进行初始化 - 否则该方法无法编译。 -
@CristiDiaconescu 如果你使用 ?。 TryGetValue 不会被调用。
-
@user6144226 当然可以,但是编译器传统上非常擅长计算常量值表达式。例如:
if( true || c.Dict.TryGetValue(key, out val) ) // compiler error, uninitialized var但if( false || c.Dict.TryGetValue(key, out val) ) // works -
@Chris 关键是,OP 在表达式中有编译时间常数
false,它仍然无法弄清楚。这不是Rand() %2 == 0或任何疯狂的东西。这是编译时间常数。
标签: c# null-propagation-operator