Оператор распространения null и foreach

Много читая об операторе распространения Null ?., я не нашел ответа, полезен ли он в следующем сценарий.

Код, который выдает:

int[] values = null;

foreach ( var i in values ) // Throws since values is null.
{
    // ...
}

Чтобы это работало, я должен добавить проверку null перед доступом к переменной values.

Скорее всего, приведенный выше код выходит за рамки проектных соображений для оператора распространения Null. И все же, чтобы быть уверенным, я должен спросить.

Мой вопрос:

Полезен ли оператор распространения Null при попытке доступа к null коллекциям в цикле foreach?


person Uwe Keim    schedule 30.12.2014    source источник
comment
Не ответ, но вы можете написать foreach ( var i in values ?? Enumerable.Empty<int>()), чтобы избежать вложенности.   -  person Sriram Sakthivel    schedule 30.12.2014
comment
Или вместо этого используйте ArrayList или List ‹T› :)   -  person boctulus    schedule 30.12.2014
comment
@Boctulus Это тоже ссылочные типы, допускающие значение NULL, понимаете?!?   -  person Uwe Keim    schedule 30.12.2014
comment
@UweKeim: Если он использует ArrayList или List ‹T›, NullReferenceException не будет выброшено, понимаете?   -  person boctulus    schedule 30.12.2014
comment
@Boctulus Конечно?   -  person Uwe Keim    schedule 30.12.2014
comment
Также см. эту проблему Roslyn: github.com/dotnet/roslyn/issues/6563   -  person Krumelur    schedule 14.01.2016


Ответы (4)


Нет. Он предназначен для обеспечения безопасного доступа к членам объекта. В этом случае вы должны проверить, является ли массив нулевым.

person Selman Genç    schedule 30.12.2014

Я нашел другой, рабочий способ:

При использовании фантастических расширений Джона Скита (и др.) MoreLinq возникает ForEachметод расширения, который я могу использовать в своем исходном примере, например:

int[] values = null;

values?.ForEach(i=> /*...*/); // Does not throw, even values is null.
person Uwe Keim    schedule 09.08.2015
comment
В System.Collections.Generic есть расширение ForEach. Больше нет необходимости использовать MoreLinq. И это также работает с нулевым распространением, не вызывая исключения. - person Azimuth; 01.02.2021

Как бы вы предложили его использовать?

Код, который вы предоставили:

int[] values = null;

foreach (var i in values)
{
    // ...
}

расширяется во что-то:

int[] values = null;

var enumerator = values.GetEnumerator();
try
{
    while (enumerator.MoveNext())
    {
        var i = enumerator.Current;
        // ...
    }
}
finally
{
    var disposable = enumerator as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}

Я думаю, вы могли бы написать что-то вроде этого:

int[] values = null;

foreach (var i in values?.)
{
    // ...
}

Компилятору пришлось бы расширить его до чего-то вроде этого:

int[] values = null;

var enumerator = values?.GetEnumerator();
try
{
    while (enumerator?.MoveNext() ?? false)
    {
        var i = enumerator.Current;
        // ...
    }
}
finally
{
    var disposable = enumerator as IDisposable;
    if (disposable != null)
    {
        disposable.Dispose();
    }
}

И имейте в виду, что:

a = b?.M();

расширяется в:

a = b == null ? null : b.M();

Если вы не хотите явно писать оператор if, вы всегда можете положиться на старый добрый оператор объединения с нулевым значением (??):

int[] values = null;

foreach (var i in values ?? Enumerable.Empty<int>())
{
    // ...
}
person Paulo Morgado    schedule 30.12.2014

Для List<T> вы можете использовать list?.ForEach(i => ...);, а для других перечислений вы можете создать собственное расширение ForEach следующим образом:

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {

    if (source == null) { return; }

    foreach (T item in source) {
        action(item);
    }
}

Вы называете это так: myPossiblyNullEnumerable.ForEach(i => ...);

Если вы хотите, чтобы ваше расширение ForEach выбрасывало при вызове нулевых перечисляемых, вы можете просто не проверять нуль и вызывать его с тем же синтаксисом elvis, что и версия List: myPossiblyNullEnumerable?.ForEach(i => ...);

person Riikka Heikniemi    schedule 16.11.2017