2015-08-28 16 views
12

Tôi đã theo dõi tính năng điều hành an toàn được thêm vào trong C# 6 với một số sở thích. Tôi đã mong chờ nó một lúc. Nhưng tôi đang tìm một số hành vi khác với tôi mong đợi. Tôi nhận ra tôi thực sự không hiểu nó hoạt động như thế nào.C# Toán tử điều hướng an toàn - điều gì đang thực sự xảy ra?

Với lớp này

class Foo { 
    public int? Measure; 
} 

Dưới đây là một số mã sử dụng các nhà điều hành mới.

Foo f = new Foo { Measure = 3 }; 
Console.WriteLine(f?.Measure); // 3 

f = new Foo { Measure = null }; 
Console.WriteLine(f?.Measure); // null 

f = null; 
Console.WriteLine(f?.Measure); // null 

Đến đây, mọi thứ hoạt động như mong đợi. ?. đang truy cập vào các thành viên khi phía bên tay trái không phải là rỗng, nếu không trả về null. Nhưng ở đây mọi thứ diễn ra theo hướng tôi không mong đợi.

var i = f?.Measure; // i is Nullable<int> 
Console.WriteLine(i.HasValue); // false 
Console.WriteLine(f?.Measure.HasValue); // null 

Cái gì?

Tại sao tôi có thể nhận được HasValue từ i, nhưng không phải từ cùng một biểu thức mà tôi đã gán cho i? Làm thế nào có thể HasValue bao giờ được null?

Chỉnh sửa: Câu hỏi thực sự của tôi là về hành vi của chương trình chứ không phải lỗi biên dịch. Tôi đã loại bỏ các nội dung bổ sung về biên dịch và tập trung câu hỏi này hẹp hơn về lý do tại sao hai kết quả khác nhau được trả về bởi những gì có vẻ giống như logic.

+0

có thể trùng lặp của [toán tử điều kiện null không hoạt động với các loại có thể vô hiệu hóa?] (Http://stackoverflow.com/questions/31811392/null-conditional-operator-not-working-with-nullable-types) – shf301

+0

Điều đó câu hỏi là về lỗi biên dịch. Vì câu hỏi thực sự của tôi không phải là về lỗi biên dịch, mà là hành vi của chương trình, tôi đã làm sáng tỏ câu hỏi của mình về hiệu ứng đó. – recursive

Trả lời

9

Hãy xem qua điều này một cách hợp lý.

var f = ???; 
var i = f?.Measure; 
var t = i.HasValue; 

Chúng tôi không biết liệu f có bị vô hiệu hay không.
1. Nếu f null, sau đó kết quả (i) là null
2. Nếu fkhông phải là null, thì kết quả (i) là một int

Do đó, i được định nghĩa là int?, và t là một bool

Bây giờ, chúng ta hãy đi bộ qua này:

var f = ???; 
var i = f?.Measure.HasValue; 
  1. Nếu f null, sau đó kết quả (i) là null
  2. Nếu fkhông phải là null, sau đó kết quả (i) là Measure.HasValue, mà là một bool.

Do đó, ibool?.

Nếu f là không, chúng tôi đoản mạch và trả về giá trị rỗng.Nếu không, chúng tôi trả lại kết quả bool của .HasValue.

Về cơ bản, khi sử dụng ?. - các kiểu trả về phải là một giá trị tham khảo, hoặc một Nullable<T>, như các biểu hiện có thể ngắn mạch để trở về null.

+1

Hm ... Đó là loại tâm-boggling với tôi, nhưng tôi nghĩ rằng tôi có thể thích nghi với hành vi đó. Nó chắc chắn khác với những gì tôi mong đợi. Nếu nó hoạt động như bạn nói nó (và nó chắc chắn dường như!) Thì 'f? .Measure' không phải là một" biểu thức con logic "của' f? .Measure.HasValue'. Có lẽ tôi sẽ thích nó theo cách này sau khi tôi nghĩ về nó trong một thời gian, nhưng bây giờ, có vẻ như khó hơn để giải thích. – recursive

+0

Tôi đồng ý rằng ban đầu nó hơi không trực quan. Bạn có thể đọc biểu thức là "Nếu f là null, trả về null. Nếu f không phải là null, hãy cho tôi biết nếu Measure có giá trị". Chỉ cần một số nhận được sử dụng để, tôi giả sử. Điều chính để nhận ra là bạn đang đọc và hiểu điều này: 'f? .Measure.HasValue' như thế này:' (f? .Measure) .HasValue', mà nó không - tương tự như cách 'var i = 1 + 2, var t = i * 3; 'khác với' var i = 1 + 2 * 3; ' – Rob

+0

Đó là so sánh hữu ích, nhưng trong ví dụ đó, ít nhất' 2 * 3' có giá trị! Tôi đã giả định rằng người truy cập thành viên phù hợp nhất không thể áp dụng trước tiên, vì không có gì để áp dụng nó cho đến khi một bên trái được áp dụng. Nói cách khác, '2' là một giá trị hoàn toàn tốt trên chính nó, nhưng' Measure' chỉ có ý nghĩa đối với một 'Foo' cụ thể. – recursive

0

Nullable<T> thực sự là cấu trúc và do đó không thể rỗng, chỉ Value có thể, vì vậy, HasValue sẽ luôn có thể truy cập được.

+0

Chắc chắn, nó có thể truy cập, như tôi đã cho thấy trong câu hỏi của tôi. Tuy nhiên, giá trị của nó thay đổi một cách bí ẩn từ 'false' thành' null'. – recursive

0
var i = f?.Measure; // i is Nullable<int> 
Console.WriteLine(i.HasValue); // false 
Console.WriteLine(f?.Measure.HasValue); // null 

Trong trường hợp này, f là rỗng.

Lý do tại sao i.HasValue trả lại false là vì i thuộc loại Nullable<int>. Vì vậy, ngay cả khi giá trị của i là null, như trong trường hợp này, i.HasValue vẫn có thể truy cập được.

Tuy nhiên, f?.Measure.HasValue ngay lập tức trả lại null sau khi f? được đánh giá. Do đó kết quả bạn nhìn thấy ở trên.

Chỉ cần trích dẫn Rob's comment:

Điều quan trọng để nhận ra là bạn đang đọc và hiểu này: f .Measure.HasValue như thế này: (? F .Measure) .HasValue, mà nó là không.

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