Проверить значение 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();
    }