Нулевой оператор распространения и foreach

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

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

int[] values = null;

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

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

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

Мой вопрос:

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

4 ответа

Решение

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

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

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

int[] values = null;

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

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

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

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>())
{
    // ...
}

За 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 => ...);

Другие вопросы по тегам