Нулевой оператор распространения и 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 => ...);