2010-06-23 4 views
8

Действительно ли оператор ?? в C# использует короткое замыкание при оценке?Использует ли оператор `` `` shortcircuiting?

var result = myObject ?? ExpressionWithSideEffects(); 

Когда myObject не равен нулю, то результат ExpressionWithSideEffects() не используется, но ExpressionWithSideEffects() пропускаются полностью?

ответ

7

Да, так оно и есть. Как всегда, спецификация языка C# является окончательным источником .

От C# 3 спецификации, раздел 7,12 (v3, а не 4, как v4 спецификация идет в динамические детали, которые не очень актуальны здесь):

Тип выражения a ?? b зависит от того, неявные преобразования доступны между типами операндов. В порядке предпочтения, тип a b - A0, A или B, где A - тип a, B - тип b (при условии, что b имеет тип), а A0 является базовым типом A, если A является нулевым типом, или A в противном случае , В частности, a ?? b обрабатывается как следующим образом:

  • Если А не обнуляемым тип или ссылочный тип, время компиляции ошибки происходит.
  • Если A является нулевым типом и существует неявное преобразование от b до A0, результатом является A0. На этапе время выполнения сначала оценивается. Если значение не равно нулю, то разворачивается тип A0, и это становится результатом. В противном случае b оценивается и преобразуется в тип A0, и это становится результатом .
  • В противном случае, если существует неявное преобразование от b до A, тип результата равен A. Во время выполнения сначала оценивается a. Если a не является нулевым, a становится результатом . В противном случае b оценивается и преобразуется в тип A, и это становится результатом .
  • В противном случае, если b имеет тип B и существует неявное преобразование от A0 до B, то результатом является B. Во время выполнения сначала оценивается a. Если a не null, то a разворачивается до типа A0 (если только A и A0 не являются одинаковыми) и преобразуется в тип B, и это результат . В противном случае b оценивается и становится результатом.
  • В противном случае a и b несовместимы, и возникает ошибка времени компиляции.

Вторая, третья и четвертая пули являются соответствующими.


Там философское обсуждение, которое будет иметься о том, что компилятор вам случится использовать это фактический источник истины ... правда о языке то, что это означало сделать или что это сейчас делает?

+0

К ножной записке ... Я думаю, именно поэтому мы все наслаждаемся тем, что Эрик Липперп был вокруг :) –

+1

@ Матвей: Одна из многих причин, да. Один интересный аспект Эрика заключается в том, что он может выступать в роли человеческого воплощения как spec *, так и компилятора ... –

10

Да, это короткое замыкание.

Вот фрагмент кода, чтобы проверить в LINQPad:

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

Первый COALESCE работает без выбрасывания исключения, а второй один делает бросок (строка имеет неверный формат).

+0

дерьмо, я чувствую себя втянутым в горизонт событий! – Will

0

Вот почему у нас есть модульное тестирование.

[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"); 
    } 

Это не лучшие имена тестов, но вы получаете эту идею. Он показывает, что короткие коалесцирующие операторы замыкаются так, как ожидалось.

+0

И я понимаю, что ArgumentException был странным выбором, это был только первый тип исключения, который приходил на ум. – CaffGeek

+3

Это не значит, что у нас есть модульное тестирование. Вот почему у нас есть спецификации языка. В частности, если бы мы имели модульное тестирование, но не специфика языка, мы бы знали только, что он делает, в случае тестирования. Однако, если бы у нас была спецификация языка, но не модульное тестирование, мы бы все равно знали, что язык должен делать в общем случае. Разумеется, модульное тестирование помогает убедиться в том, что компилятор действительно реализует спецификацию языка ... но я всегда предпочел бы достичь спецификации, чем единичный тест для таких вопросов. –

+0

@ Jon Skeet, коснитесь. Мне все еще нравится писать быстрые тесты, чтобы проверить, что я не уверен. Я не обязательно буду поддерживать это. И всегда возможно, что компилятор реализовал спецификацию неправильно ... – CaffGeek

Смежные вопросы