Подтвердить что ты не робот

Оператор нулевого распространения и foreach

Чтение много о Операторе Null распространения ?., я не нашел ответа, полезно ли это в следующем сценарии.

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

int[] values = null;

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

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

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

Мой вопрос:

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

int[] values = null;

values?.ForEach(i=> /*...*/); // Does not throw, even values is null.

Ответ 3

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

Код, который вы указали:

int[] values = null;

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

enxpands во что-то:

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, вы всегда можете положиться на старый добрый оператор null-coalescing (??):

int[] values = null;

foreach (var i in values ?? Enumerable.Empty<int>())
{
    // ...
}

Ответ 4

Для 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 => ...);