2016-07-05 23 views
33

我是新的C#和同時探索的語言特點,我碰到一些奇怪的事情就來了:爲什麼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 
    } 
} 

任何人都可以向我解釋爲什麼需要括號?

+1

在您試圖訪問一個名爲'Value'在'Foo'成員,不存在第一種情況下的實際結果。在第二種說法中,「價值」指的是「可空的」的屬性。 – xfx

+9

如果你真的考慮過這個問題,在包含null條件運算符的表達式上調用'.Value'是相互矛盾的(你可能期望null或者你沒有)。你很可能會想用一個空合併運算符來代替,在這種情況下,不需要括號。例如:'Foo foo2 = foo?.Identity()?? '; – sstan

回答

41

任何人都可以向我解釋爲什麼需要括號嗎?

由於Identity()回報Foo(不是Foo?),並且因此不具有Value屬性。如果foo爲空,則null將通過Identity調用傳播。

當你把它周圍的括號中,表達的結果是Nullable<Foo>確實Value財產。

還要注意的是,如果foo空,那麼你會在Nullable<Foo>沒有值調用Value,並會在運行時得到一個異常。一些靜態分析器會認識到您有一個可能的空引用異常等待發生並警告您。

如果它們擴展到它們的等同沒有空置的傳播將更加明確:

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 
} 
+0

使用相同符號表示不同運營商的樂趣。 – BoltClock

+0

你贏了我的電腦和網絡非常慢:) –

+0

如果'Identity()'返回'Foo',爲什麼'Foo foo3 = foo?.Identity();'不能編譯? – Lukas92

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 
    } 
} 

如果您並不需要括號訪問可空的結果,您將無法訪問ID屬性。由於下面將無法編譯:

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

當你寫foo?.Identity().什麼是後.Identity()返回Foo類型。然而,在(foo?.Identity()).什麼.Foo?這是整個聲明foo?.Identity().

相關問題