为什么C#在表达式中使用nullables时需要括号?

时间:2016-07-05 14:08:34

标签: c# nullable

我是C#的新手,在探索语言功能时,我遇到了一些奇怪的事情:

struct Foo
{
    public Foo Identity() { return this; }

    public static void Bar(Foo? foo)
    {
        Foo foo1 = foo?.Identity().Value; // Does not compile
        Foo foo2 = (foo?.Identity()).Value; // Compiles
    }
}

有人可以向我解释为什么需要括号吗?

2 个答案:

答案 0 :(得分:40)

  

有人可以向我解释为什么需要括号吗?

因为Identity()返回Foo(不是Foo?),因此没有Value属性。如果foo为空,则null将通过Identity调用传播。

当你在它周围添加括号时,表达式的结果是Nullable<Foo>,其中 具有Value属性。

另请注意,如果foo 为null,那么您将在没有值的Value上调用Nullable<Foo>,并将获得异常< em>在运行时。一些静态分析器会识别出您可能存在等待发生的空引用异常,并向您发出警告。

如果将它们扩展为等效而没有空传播,则会更清楚:

Foo foo1;
if(foo != null)
{
    foo1 = foo.Identity().Value;  // not possible - Foo has no Value property.
}
else
{
    foo1 = null;  // also not possible 
}

Foo foo2;
Foo? temp;
if(foo != null)
{
    temp = foo.Identity();
}
else
{
   temp = null;  // actually a Nullable<Foo> with no value
}
foo2 = temp.Value;  // legal, but will throw an exception at run-time if foo is null
  

如果Identity()返回Foo,为什么Foo foo3 = foo?.Identity();无法编译?

相当于:

Foo foo3
if(foo != null)
{
    foo3 = foo.Identity();
}
else
{
    foo3 = null;  // not possible 
}

答案 1 :(得分:0)

我认为c#团队做出这样做是一个很好的决定。请考虑以下情况:

如果结构是:

struct Foo
{
    public int ID { set; get; }

    public Foo Identity() { return this; }

    public static void Bar(Foo? foo)
    {
        int? foo1 = foo?.Identity().ID; // compile
        Foo foo2 = (foo?.Identity()).Value; // Compiles
    }
}

如果您不需要括号来访问Nullable结果,那么您将无法访问ID属性。由于以下内容无法编译:

int? foo2 = (foo?.Identity()).GetValueOrDefault()?.ID

当您在foo?.Identity(). .返回的Foo类型Identity()之后写下(foo?.Identity()).时的内容。但是在. Foo? foo?.Identity().之后的内容是整个陈述的实际结果{{1}}