空传播运算符,输出参数和错误的编译器错误?
假设我有一个具有Dictionary
类型属性的类,它可以为null。
这会编译但是对TryGetValue()
的调用可能会在运行时抛出NullRef
exception:
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 }
通过将val
初始化为erhm,value(例如, String.Empty
),编译器能够理解null运算符的意图并按预期运行(通过LINQPad,natch):
void Main() { MyClass c = new MyClass(); string val = string.Empty; if (c.PossiblyNullDictionary?.TryGetValue("someKey", out val) ?? false) { Console.WriteLine(val); } } public class MyClass { public Dictionary PossiblyNullDictionary; } // Define other methods and classes here
Ed:通过’grok the intent’我的意思是编译器不能对程序的特性做出重要保证,如果它允许执行将当前作用域保留为未初始化的val
。 当它评估null运算符时,方法调用。
你要求的用例是这样的: bool SomeMethod(string s, out v)
TryGetValue,我们有bool SomeMethod(string s, out v)
。 让我们说,当被调用时, SomeMethod
是顽皮的,只是有一个return true;
的体return true;
。 编译器将方法调用主体视为不透明(因为它可能并不总是在编译器可用/可见的程序集中),因此它得出结论,无法certificateval
已初始化。
ed:在回复一些评论时,我想更新我的回答,指出这种行为并不是特定的??
还是?.
C#语言function; 只需使用三元表达式即可重现相同的效果:
c.PossiblyNullDictionary == null ? false : c.PossiblyNullDictionary.TryGetValue("someKey", out val) //error: use of possibly uninitialized local variable
好像你遇到了编译器理解的限制?.
和??
这并不太令人惊讶,因为它们并没有真正完全融入语言。
如果在没有较新的运算符的情况下使测试显式,编译器将同意您的意见:
MyClass c = new MyClass(); string val; if (c.PossiblyNullDictionary != null && c.PossiblyNullDictionary.TryGetValue("someKey", out val)) { Console.WriteLine(val); // now okay }
那是因为如果c.PossiblyNullDictionary为null,则不会执行TryGetValue,并且该表达式不会返回true或false。
c.PossiblyNullDictionary? TryGetValue(“someKey”,out val)返回Nullable,你可以用这样的东西替换你的代码并编译:
string val; var result = c.PossiblyNullDictionary?.TryGetValue("key", out val); if (result.HasValue && result.Value) { }