2016-07-05 14 views
33

Tôi mới đến C# và trong khi khám phá các tính năng ngôn ngữ, tôi đi qua một cái gì đó kỳ lạ:Tại sao C# yêu cầu dấu ngoặc đơn khi sử dụng các giá trị rỗng trong một biểu thứ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 
    } 
} 

bất cứ ai có thể giải thích cho tôi tại sao ngoặc là cần thiết?

+1

Trong trường hợp đầu tiên bạn đang cố truy cập thành viên có tên 'Giá trị' trong' Foo', không tồn tại. Trong câu lệnh thứ hai, 'Giá trị' là một thuộc tính của' Nullable '. – xfx

+9

Nếu bạn thực sự nghĩ về nó, gọi '.Value' trên một biểu thức bao gồm toán tử điều kiện null là mâu thuẫn (bạn hoặc mong đợi một null hoặc bạn không).Bạn rất có thể muốn sử dụng toán tử kết hợp rỗng thay vào đó, trong trường hợp này không cần dấu ngoặc đơn. ví dụ: 'Foo foo2 = foo? .Identity() ?? '; – sstan

Trả lời

41

Ai đó có thể giải thích cho tôi lý do tại sao dấu ngoặc đơn là cần thiết không?

Identity() lợi nhuận một Foo (không phải là một Foo?) và do đó không có tài sản Value. Nếu foo là null, giá trị null sẽ truyền qua cuộc gọi Identity.

Khi bạn đặt dấu ngoặc xung quanh nó, kết quả của các biểu là một Nullable<Foo>không có một tài sản Value.

Cũng lưu ý rằng nếu foo null, sau đó bạn sẽ được gọi Value trên Nullable<Foo> rằng không có giá trị, và sẽ nhận được một ngoại lệ tại thời gian chạy. Một số máy phân tích tĩnh sẽ nhận ra rằng bạn có một ngoại lệ tham chiếu null có thể chờ đợi để xảy ra và cảnh báo bạn.

Nếu bạn mở rộng ảnh ra tương đương của họ mà không null-tuyên truyền nó sẽ được rõ ràng hơn:

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 

Nếu Identity() lợi nhuận Foo, tại sao Foo foo3 = foo?.Identity(); không biên dịch?

Tương đương với đó sẽ là:

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

Niềm vui của việc sử dụng cùng một biểu tượng để có nghĩa là các toán tử khác nhau. – BoltClock

+0

Bạn thắng máy tính và mạng rất chậm của tôi :) –

+0

Nếu 'Identity()' trả về 'Foo', tại sao' Foo foo3 = foo? .Identity(); 'không biên dịch? – Lukas92

0

Tôi nghĩ đó là một quyết định tốt từ nhóm C# để làm điều đó theo cách này. Xem xét kịch bản sau đây:

Nếu struct là:

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

Nếu bạn không cần ngoặc để truy cập kết quả Nullable, bạn sẽ không thể truy cập vào ID tài sản. Kể từ khi dưới đây sẽ không biên dịch:

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

Khi bạn viết foo?.Identity(). những gì là sau khi . là loại Foo trả về bởi Identity(). Tuy nhiên, trong (foo?.Identity()). nội dung sau .Foo? là kết quả thực tế của toàn bộ tuyên bố foo?.Identity().

Các vấn đề liên quan