Является ли if (items! = Null) лишним перед foreach (T item в items)? - PullRequest
77 голосов
/ 23 июня 2011

Я часто сталкиваюсь с кодом, подобным следующему:

if ( items != null)
{
   foreach(T item in items)
   {
        //...
   }
}

В принципе, условие if гарантирует, что блок foreach будет выполняться, только если items не равно нулю.Мне интересно, действительно ли необходимо условие if, или foreach справится со случаем, если items == null.

Я имею в виду, могу ли я просто написать

foreach(T item in items)
{
    //...
}

, не заботясь о том, является ли items нулем или нет?Является ли условие if лишним?Или это зависит от типа из items или от T?

Ответы [ 12 ]

87 голосов
/ 23 июня 2011

Вам все еще нужно проверить, если (items! = Null), иначе вы получите NullReferenceException. Однако вы можете сделать что-то вроде этого:

List<string> items = null;  
foreach (var item in items ?? new List<string>())
{
    item.Dump();
}

но вы можете проверить его производительность. Поэтому я все еще предпочитаю сначала иметь if (items! = Null).

Исходя из предположения Эрика Липперта, я изменил код на:

List<string> items = null;  
foreach (var item in items ?? Enumerable.Empty<string>())
{
    item.Dump();
}
49 голосов
/ 21 августа 2015

Используя C # 6, вы можете использовать новый нулевой условный оператор вместе с List<T>.ForEach(Action<T>) (или вашим собственным IEnumerable<T>.ForEach методом расширения).

List<string> items = null;
items?.ForEach(item =>
{
    // ...
});
33 голосов
/ 23 июня 2011

Реальный вывод здесь должен быть последовательность почти никогда не должна быть нулевой с самого начала . Просто сделайте его инвариантом во всех ваших программах, чтобы, если у вас была последовательность, она никогда не была нулевой. Он всегда инициализируется пустой последовательностью или какой-либо другой подлинной последовательностью.

Если последовательность никогда не равна нулю, то, очевидно, вам не нужно проверять ее.

9 голосов
/ 23 июня 2011

На самом деле есть запрос функции для этого @Connect: http://connect.microsoft.com/VisualStudio/feedback/details/93497/foreach-should-check-for-null

И ответ вполне логичен:

Я думаю, что большинство циклов foreach написано с целью итерации ненулевая коллекция. Если вы попытаетесь перебирая ноль, вы должны получить ваше исключение, так что вы можете исправить ваш код.

5 голосов
/ 23 июня 2011

Вы всегда можете проверить это с пустым списком ... но это то, что я нашел на веб-сайте msdn

foreach-statement:
    foreach   (   type   identifier   in   expression   )   embedded-statement 

Если выражение имеет значение null, System.NullReferenceExceptionброшенный.

2 голосов
/ 30 июня 2011

Вы можете инкапсулировать нулевую проверку в методе расширения и использовать лямбду:

public static class EnumerableExtensions {
  public static void ForEach<T>(this IEnumerable<T> self, Action<T> action) {
    if (self != null) {
      foreach (var element in self) {
        action(element);
      }
    }
  }
}

Код становится:

items.ForEach(item => { 
  ...
});

Если можно быть еще более кратким, если вы хотите просто вызвать метод, который берет элемент и возвращает void:

items.ForEach(MethodThatTakesAnItem);
2 голосов
/ 23 июня 2011

Это не лишнее.Во время выполнения элементы будут преобразованы в IEnumerable и будет вызван его метод GetEnumerator.Это приведет к разыменованию элементов, которые потерпят неудачу

1 голос
/ 23 июня 2011

Тебе это нужно.В противном случае вы получите исключение, когда foreach получит доступ к контейнеру, чтобы настроить итерацию.

Под прикрытием foreach использует интерфейс, реализованный в классе коллекции , для выполненияитерация.Общий эквивалентный интерфейс: здесь .

Оператор foreach языка C # (для каждого в Visual Basic) скрывает сложность перечислителей.Поэтому рекомендуется использовать foreach вместо непосредственного управления перечислителем.

0 голосов
/ 28 июля 2015

В C # 6 вы можете написать вот что:

// some string from file or UI, i.e.:
// a) string s = "Hello, World!";
// b) string s = "";
// ...
var items = s?.Split(new char[] { ',', '!', ' ' }) ?? Enumerable.Empty<string>();  
foreach (var item in items)
{
    //..
}

Это в основном решение Влада Бездена, но с использованием ?? выражение, чтобы всегда генерировать массив, который не является нулевым и, следовательно, сохраняется в foreach, вместо того, чтобы иметь эту проверку внутри скобки foreach.

0 голосов
/ 23 июня 2011

Как уже упоминалось здесь вам необходимо проверить, не является ли оно нулевым.

Не используйте выражение, которое оценивается как нулевое.

...