Проверить значение null в цикле foreach
Есть ли лучший способ сделать следующее:
Мне нужно проверить, что null должно произойти на file.Headers, прежде чем продолжить цикл
if (file.Headers != null)
{
foreach (var h in file.Headers)
{
//set lots of properties & some other stuff
}
}
Короче, выглядит немного уродливым, чтобы написать foreach внутри if из-за уровня отступов, происходящих в моем коде.
Что-то, что можно было бы оценить
foreach(var h in (file.Headers != null))
{
//do stuff
}
возможно?
Ответы
Ответ 1
Как небольшое косметическое дополнение к предложению Руны, вы можете создать свой собственный метод расширения:
public static IEnumerable<T> OrEmptyIfNull<T>(this IEnumerable<T> source)
{
return source ?? Enumerable.Empty<T>();
}
Затем вы можете написать:
foreach (var header in file.Headers.OrEmptyIfNull())
{
}
Измените имя по вкусу:)
Ответ 2
Предполагая, что тип элементов в file.Headers - T, вы можете сделать это
foreach(var header in file.Headers ?? Enumerable.Empty<T>()){
//do stuff
}
это создаст пустое перечисляемое значение T, если file.Headers имеет значение null. Если тип файла является типом, которым вы владеете, я бы, однако, вместо этого рассмотрел вопрос об изменении метода получения Headers
. null
- это значение unknown, поэтому, если это возможно, вместо использования null как "Я знаю, что нет элементов", когда на самом деле (/первоначально) null следует интерпретировать как "Я не знаю, есть ли какие-либо элементы", используйте пустой набор для покажите, что вы знаете, что в наборе нет элементов. Это также было бы DRY'er, так как вам не придется делать нулевую проверку так часто.
РЕДАКТИРОВАТЬ в качестве дополнения к предложению Jons, вы также можете создать метод расширения, изменив приведенный выше код на
foreach(var header in file.Headers.OrEmptyIfNull()){
//do stuff
}
В случае, если вы не можете изменить геттер, я бы предпочел это, так как он более четко выражает намерение, давая операции имя (OrEmptyIfNull)
Упомянутый выше метод расширения может сделать невозможной определенную оптимизацию для обнаружения оптимизатором. В частности, те, которые связаны с IList с использованием перегрузки методов, могут быть устранены
public static IList<T> OrEmptyIfNull<T>(this IList<T> source)
{
return source ?? Array.Empty<T>();
}
Ответ 3
Честно говоря, я советую: просто вскочите тест null
. Тест null
просто a brfalse
или brfalse.s
; все остальное будет включать гораздо больше работы (тесты, назначения, дополнительные вызовы методов, ненужные GetEnumerator()
, MoveNext()
, Dispose()
на итераторе и т.д.).
Тест An if
прост, понятен и эффективен.
Ответ 4
"if" до итерации в порядке, некоторые из этих "симпатичных" семантик могут сделать ваш код менее удобочитаемым.
в любом случае, если отступ беспокоит вас, вы можете изменить if, чтобы проверить:
if(file.Headers == null)
return;
и вы попадете в цикл foreach только тогда, когда в свойстве заголовков есть истинное значение.
Другая возможность, о которой я могу думать, - использовать оператор с нулевым коалесцированием внутри вашего цикла foreach и полностью исключить нулевую проверку.
Образец:
List<int> collection = new List<int>();
collection = null;
foreach (var i in collection ?? Enumerable.Empty<int>())
{
//your code here
}
(замените коллекцию на ваш истинный объект/тип)
Ответ 5
Я использую хороший небольшой метод расширения для этих сценариев:
public static class Extensions
{
public static IList<T> EnsureNotNull<T>(this IList<T> list)
{
return list ?? new List<T>();
}
}
Учитывая, что заголовки имеют список типов, вы можете сделать следующее:
foreach(var h in (file.Headers.EnsureNotNull()))
{
//do stuff
}
Ответ 6
Использование Null-условного оператора и ForEach(), который работает быстрее, чем стандартный цикл foreach.
Вы должны бросить коллекцию в список, хотя.
listOfItems?.ForEach(item => // ... );
Ответ 7
В некоторых случаях я предпочел бы немного другой, универсальный вариант, предполагая, что, как правило, конструкторы коллекции по умолчанию возвращают пустые экземпляры.
Было бы лучше назвать этот метод NewIfDefault
. Это может быть полезно не только для коллекций, поэтому ограничение типа IEnumerable<T>
может быть избыточным.
public static TCollection EmptyIfDefault<TCollection, T>(this TCollection collection)
where TCollection: class, IEnumerable<T>, new()
{
return collection ?? new TCollection();
}