2010-06-23 40 views
8

Nhà điều hành ?? trong C# có sử dụng shortcircuiting khi đánh giá không?Toán tử `` ?? `` có sử dụng shortcircuiting không?

var result = myObject ?? ExpressionWithSideEffects(); 

Khi myObject là không null, kết quả của ExpressionWithSideEffects() không được sử dụng, nhưng sẽ ExpressionWithSideEffects() bị bỏ qua hoàn toàn?

Trả lời

7

Có. Như mọi khi, đặc tả ngôn ngữ C# là nguồn dứt khoát .

Từ C# 3 spec, phần 7.12 (V3 chứ không phải là 4, như spec v4 đi vào chi tiết năng động mà không thực sự liên quan ở đây):

Kiểu của biểu thức a ?? b phụ thuộc vào chuyển đổi tiềm ẩn có sẵn giữa các loại toán hạng. Theo thứ tự ưu tiên, loại của một ?? b là A0, A hoặc B, trong đó A là loại a, B là loại b (với điều kiện b có kiểu), và A0 là kiểu cơ bản của A nếu A là một kiểu nullable, hoặc A nếu không . Cụ thể, a ?? b được xử lý như sau:

  • Nếu A không phải là một loại nullable hoặc một loại tài liệu tham khảo, một lỗi thời gian biên dịch xảy ra.
  • Nếu A là loại có thể vô hiệu và chuyển đổi ẩn tồn tại từ b đến A0, loại kết quả là A0. Tại thời gian chạy, một lần đầu tiên được đánh giá. Nếu số không phải là null, thì không được để loại A0 và điều này trở thành kết quả. Nếu không, b được đánh giá và được chuyển thành loại A0 và kết quả này sẽ trở thành kết quả là .
  • Nếu không, nếu chuyển đổi ẩn tồn tại từ b đến A, loại kết quả là A. Khi chạy, giá trị đầu tiên được đánh giá. Nếu không có giá trị rỗng, a sẽ trở thành kết quả . Nếu không, b được đánh giá và được chuyển thành loại A và kết quả này sẽ trở thành kết quả là .
  • Nếu không, nếu b có loại B và chuyển đổi ẩn tồn tại từ A0 đến B, loại kết quả là B. Khi chạy, lần đầu tiên được đánh giá. Nếu a không phải là null, thì không được để loại A0 (trừ khi A và A0 cùng loại) và chuyển thành loại B, và điều này trở thành kết quả. Nếu không, b là được đánh giá và trở thành kết quả.
  • Nếu không, a và b không tương thích và xảy ra lỗi biên dịch.

Dấu đầu dòng thứ hai, thứ ba và thứ tư là những dấu có liên quan.


Có một cuộc thảo luận triết học để có được về việc liệu trình biên dịch bạn tình cờ được sử dụng là thực tế nguồn gốc của sự thật ... là sự thật về một ngôn ngữ gì nó có nghĩa làm hoặc những gì hiện tại hiện?

+0

Để lưu ý chân ... Tôi nghĩ đó là lý do tại sao tất cả chúng ta đều thích Eric Lippert ở xung quanh :) –

+1

@Matthew: Một trong nhiều lý do, vâng. Một khía cạnh thú vị của Eric là anh ta có thể đóng vai trò là hóa thân con người của cả trình biên dịch * và * trình biên dịch ... –

10

Có, nó không đoản mạch.

Dưới đây là một đoạn để kiểm tra trong LinqPad:

string bar = "lol"; 
string foo = bar ?? string.Format("{2}", 1); 
foo.Dump(); 
bar = null; 
foo = bar ?? string.Format("{2}", 1); 
foo.Dump(); 

Các liên hiệp đầu tiên hoạt động mà không ném một ngoại lệ trong khi cái thứ hai không ném (chuỗi định dạng không hợp lệ).

+0

crap, tôi có thể cảm thấy mình bị kéo vào chân trời sự kiện! – Will

0

Đây là lý do tại sao chúng tôi có thử nghiệm đơn vị.

[TestMethod] 
    public void ShortCircuitNullCoalesceTest() 
    { 
     const string foo = "foo"; 
     var result = foo ?? Bar(); 
     Assert.AreEqual(result, foo); 
    } 

    [TestMethod] 
    [ExpectedException(typeof(ArgumentException))] 
    public void ShortCircuitNullCoalesceFails() 
    { 
     const string foo = null; 
     var result = foo ?? Bar(); 
    } 

    private static string Bar() 
    { 
     throw new ArgumentException("Bar was called"); 
    } 

Đây không phải là tên thử nghiệm tốt nhất, nhưng bạn có ý tưởng. Nó cho thấy rằng các toán tử kết hợp ngắn mạch như mong đợi.

+0

Và tôi nhận ra ArgumentException là một sự lựa chọn kỳ quặc, nó chỉ là loại ngoại lệ đầu tiên mà bạn cần chú ý. – CaffGeek

+3

Đây không phải là lý do tại sao chúng tôi có thử nghiệm đơn vị. Đây là lý do tại sao chúng tôi có thông số kỹ thuật ngôn ngữ. Đặc biệt, nếu chúng tôi có thử nghiệm đơn vị nhưng không có thông số ngôn ngữ, chúng tôi sẽ chỉ biết điều gì sẽ xảy ra trong trường hợp đang được kiểm tra. Nếu chúng tôi có thông số ngôn ngữ nhưng không có kiểm tra đơn vị, tuy nhiên, chúng tôi vẫn sẽ biết ngôn ngữ có ý nghĩa gì trong trường hợp chung. Phải thừa nhận rằng thử nghiệm đơn vị giúp xác minh rằng trình biên dịch thực sự triển khai đặc tả ngôn ngữ ... nhưng tôi luôn muốn tiếp cận với spec hơn là kiểm tra đơn vị cho các câu hỏi như thế này. –

+0

@Jon Skeet, touche. Tôi vẫn thích viết các bài kiểm tra nhanh để xác minh những điều tôi không chắc chắn. Tôi sẽ không nhất thiết phải giữ nó xung quanh. Và nó luôn luôn có thể là trình biên dịch thực hiện các spec không đúng cách ... – CaffGeek

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