Что подразумевается под коротким замыканием нулевого условного оператора?

Примечание для будущих посетителей: этот вопрос был основан на ошибочном коде воспроизведения. Оператор ?. действительно делает короткое замыкание. Теперь вы можете закрыть эту вкладку браузера.


В Интернете есть много источников, утверждающих, что условный оператор null (?.) приводит к короткому замыканию (например, http://www.informit.com/articles/article.aspx?p=2421572, выполните поиск по запросу "схема"). Я не могу обнаружить ничего подобного:

    static void Main()
    {
        var c = new C();

        Console.WriteLine(c?.Inner?.Inner); //does not rely on short circuiting, works
        Console.WriteLine(c?.Inner.Inner); //throws NullReferenceException
    }

    class C
    {
        public C Inner;
    }

Здесь первая строка работает из-за второй ?.. Второй ?. увидел null в качестве своего первого операнда и, следовательно, также вернул null. Это не короткое замыкание.

Судя по всему, остальная часть цепочки выполняется, даже если сработал нулевой регистр. Цепочка не обрывается. Для меня короткое замыкание означает, что цепочка прервана. MSDN утверждает, что это так, но пример кода не демонстрирует краткое схема:

//The last example demonstrates that the null-condition operators are short-circuiting
int? count = customers?[0]?.Orders?.Count();
// null if customers, the first customer, or Orders is null

Изменялось ли когда-либо это поведение в течение цикла разработки C# 6? Это объясняет плохие источники в сети. И почему так много говорят о коротком замыкании, если его нет? Возможно, я что-то не так понял.

Это не дубликат, потому что речь идет о короткое замыкание у оператора или нет (ответ: нет, хотя в принятом ответе об этом не говорится). Этот кандидат касается логических значений, допускающих значение NULL, и других несвязанный.


person boot4life    schedule 24.06.2016    source источник
comment
Я бы посоветовал вам еще раз прочитать статью, на которую вы ссылаетесь.   -  person Ivan Stoev    schedule 24.06.2016
comment
@IvanStoev что-нибудь более конкретное? Не знаю, что мне делать с этим комментарием. Ясно, я что-то не понимаю, но это не проясняет для меня.   -  person boot4life    schedule 24.06.2016
comment
Это из ссылки: Нулевой условный оператор короткого замыкания, что означает, что вы можете связать несколько ?. операторы, зная, что первое обнаруженное значение NULL препятствует вычислению оставшихся (самых правых) компонентов выражения. Обратите внимание на множитель цепи.   -  person Ivan Stoev    schedule 24.06.2016
comment
@IvanStoev Я понимаю претензию. Я не согласился с этим, потому что мой эксперимент был неверным, что я теперь знаю. Проблема не в том, что я неправильно понял статью.   -  person boot4life    schedule 24.06.2016
comment
На самом деле строка с комментарием //does not rely on short circuiting, works основана на коротком замыкании.   -  person Ivan Stoev    schedule 24.06.2016
comment
Я не согласен с этой позицией. Я объяснил в комментариях ниже, почему. Не уверен, почему он будет называться SC, если все экземпляры ?. необходимы. Кроме того, этот код в любом случае не демонстрирует мою (ложную) точку зрения, потому что я должен был добавить еще один .Inner. Это демонстрирует SC: c.Inner?.Inner.Inner.   -  person boot4life    schedule 24.06.2016


Ответы (3)


Это действительно короткое замыкание (если под этим мы подразумеваем «завершить цепочку вызовов»).

Рассмотрим этот код:

using System;

namespace ConsoleApplication1
{
    class C
    {
        public C Inner
        {
            get
            {
                Console.WriteLine("Inner called.");
                return this; // Change this to `return null;`
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var c = new C();

            var x = c?.Inner?.Inner?.Inner;
        }
    }
}

Запустите это, и оно напечатает

Inner called.
Inner called.
Inner called.

Теперь измените return this; на return null;, и он напечатает

Inner called.

тем самым демонстрируя, что цепочка вызовов была остановлена ​​при первом нулевом значении.

Теперь измените выражение на:

var x = c?.Inner?.Inner.Inner;

и все равно будет печатать

Inner called.

потому что это короткое замыкание.

Очевидно, что он должен получить доступ к Inner по крайней мере один раз, чтобы увидеть, является ли он нулевым. Если сам c равен нулю, то Inner вообще не используется.

Обратите внимание, что с учетом выражения:

var x = c?.Inner.Inner;

он выдаст исключение нулевой ссылки при первом использовании .Inner, потому что он уже проверил, что c не является нулевым, используя c?, и теперь он продолжает использовать .Inner.

Если бы c было нулевым, он бы вообще не обращался к .Inner из-за c?..

person Matthew Watson    schedule 24.06.2016
comment
Смотрите мой комментарий к другому ответу. Это не короткое замыкание. Здесь необходимы все экземпляры ?., чтобы избежать сбоя. Если бы мы действительно наблюдали SC, то потребовался бы только первый ?.. - person boot4life; 24.06.2016
comment
Другими словами: как бы вы разработали тест, чтобы увидеть, есть ли SC или нет? Как вы определяете СК? Я определяю это как остальную часть цепочки, отменяемую одним оператором ?.. - person boot4life; 24.06.2016
comment
@boot4life всегда отменяется одним ?.. Просто каждый раз это может быть разное ?. в зависимости от того, что такое null. - person i3arnon; 24.06.2016
comment
Тогда давайте поговорим о конкретном случае из моего вопроса. Если первый ?. SC, как вы утверждаете, зачем нужен второй? - person boot4life; 24.06.2016
comment
@boot4life Потому что первый работает с тем, что не null, а второй — с тем, что является null. - person i3arnon; 24.06.2016
comment
Ааа это плохо. Мой код не показывает то, что я хочу показать. Сейчас будут исследовать. - person boot4life; 24.06.2016
comment
@boot4life c?. проверяет значение c, но не проверяет значение Inner. Только Inner?. проверит значение Inner. На самом деле это довольно просто - ?. проверяет элемент слева от него, и если он равен нулю, он останавливается и возвращает значение null. - person Matthew Watson; 24.06.2016
comment
Я понимаю, что вы двое утверждаете. Я могу воспроизвести это на своем игрушечном примере. Дело в реальном коде, который не подходит для публикации, потому что он огромен, я думаю, что наблюдаю поведение не SCing. Ясно, что я ошибаюсь в этом, но именно это привело к этому вопросу (кроме того, мое воспроизведение было неправильным, чего я не заметил. Это ввело меня в заблуждение, ложно подтвердив мое ложное убеждение). - person boot4life; 24.06.2016
comment
Возможно, компилятор C# делает что-то странное. Отражатель аварийно завершает работу при декомпиляции метода. - person boot4life; 24.06.2016
comment
Я буду продолжать исследовать то, что я вижу. На вопрос, наконец, дан ответ из-за того, что мое непонимание обнаружилось. Спасибо. - person boot4life; 24.06.2016

Короткое замыкание здесь означает, что когда у вас есть, например, obj?.Property1?.Property2?.Property3, а obj равно null, тогда все выражение возвращает null, и никакие другие свойства не вызываются (поскольку они будут генерировать).

Это короткое замыкание может произойти на каждом ?. в зависимости от того, какая часть null. если obj не равно нулю, а первый Property равен, то только остальные 2 не будут вызываться. То же самое для второго и так далее.

Короткое замыкание происходит в выражении, а не в остальных операторах после этого выражения.

person i3arnon    schedule 24.06.2016

Проще говоря, короткое замыкание — это гарантия того, что если он определит, что одно свойство имеет значение null, он не будет продолжать попытки оценить остальные.

Это может быть понятнее с примером, который не включает нулевой оператор.

В приведенном ниже примере мы проверяем, является ли x значением null, прежде чем проверять значение его свойства.

if(x != null & x.SomeProperty == 1)

Но это все равно вызовет исключение, если x равно null, потому что он будет оценивать оба условия. Даже если x равно нулю, он все равно попытается проверить x.SomeProperty и выдаст NullReferenceException.

Но если вместо этого мы используем оператор &&

if(x != null && x.SomeProperty == 1)

Потом "короткое замыкание". Если первое условие неверно, то второе условие даже не будет оцениваться. Он проверяет, верны ли они оба. Но если первое неверно, то они оба не могут быть правдой — значение второго не имеет значения. Таким образом, он останавливается после первого условия.

Короткое замыкание в конечном итоге означает, что если он оценивает что-либо, что делает остальные условия неактуальными, то он гарантированно не оценивает оставшиеся условия.

person Scott Hannen    schedule 24.06.2016
comment
Я понимаю, что такое SC (и я описал, что это такое в вопросе). Я думал, что код в вопросе демонстрирует, что его там нет. Но код был неверным, и он там. - person boot4life; 25.06.2016