空传播运算符,输出参数和错误的编译器错误?

时间:2017-12-06 22:49:57

标签: c# null-propagation-operator

假设我有一个类Dictionary<string,string>属性的类,可能为null。

这会编译,但对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

}

3 个答案:

答案 0 :(得分:4)

似乎你已经遇到了编译器对?.??的理解的限制,这并不太令人惊讶,因为它们并没有真正完全融入语言

如果在没有较新运算符的情况下使测试显式化,编译器将同意您:

MyClass c = new MyClass();
string val;
if (c.PossiblyNullDictionary != null && c.PossiblyNullDictionary.TryGetValue("someKey", out val)) {
    Console.WriteLine(val); // now okay
}

答案 1 :(得分:2)

通过将val初始化为erhm,值(例如,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<string, string> PossiblyNullDictionary;
}
// Define other methods and classes here
爱德:通过&#39; grok意图&#39;我的意思是,如果编译器允许执行使val未初始化的当前作用域,编译器就无法对程序的特征做出重要保证。当它评估null运算符时,方法调用。

您要求的用例是: 假设我们没有TryGetValue,而是bool SomeMethod(string s, out v)。让我们说,在调用时,SomeMethod是顽皮的,只有一个return true;的正文。编译器将方法调用主体视为不透明(因为它可能并不总是在编译器可用/可见的程序集中),因此它得出的结论是,无法证明val已被初始化。 / p>

ED: 在回复一些评论时,我想更新我的回答,指出此行为并非针对???. C#语言功能;只需使用三元表达式即可重现相同的效果:

c.PossiblyNullDictionary == null ? 
    false : 
    c.PossiblyNullDictionary.TryGetValue("someKey", out val) 
 //error: use of possibly uninitialized local variable

答案 2 :(得分:-3)

那是因为如果c.PossiblyNullDictionary为null,则TryGetValue不会被执行,并且该表达式不会返回true或false。

c.PossiblyNullDictionary? TryGetValue(&#34; someKey&#34;,out val)返回Nullable,你可以用这样的代码替换你的代码并编译:

        string val;
        var result = c.PossiblyNullDictionary?.TryGetValue("key", out val);
        if (result.HasValue && result.Value)
        {

        }