c# - foreach null php




Почему.NET foreach loop выбрасывает NullRefException, когда коллекция имеет значение null? (8)

Другой метод расширения для этого:

public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
    if(items == null) return;
    foreach (var item in items) action(item);
}

Потребляйте несколькими способами:

(1) методом, который принимает T :

returnArray.ForEach(Console.WriteLine);

(2) с выражением:

returnArray.ForEach(i => UpdateStatus(string.Format("{0}% complete", i)));

(3) с многострочным анонимным методом

int toCompare = 10;
returnArray.ForEach(i =>
{
    var thisInt = i;
    var next = i++;
    if(next > 10) Console.WriteLine("Match: {0}", i);
});

Поэтому я часто сталкиваюсь с этой ситуацией ... где Do.Something(...) возвращает нулевую коллекцию, например:

int[] returnArray = Do.Something(...);

Затем я пытаюсь использовать эту коллекцию так:

foreach (int i in returnArray)
{
    // do some more stuff
}

Мне просто интересно, почему не может цикл foreach работать с нулевой коллекцией? Мне кажется логичным, что 0 итераций будут выполняться с нулевым набором ... вместо этого он выдает NullReferenceException . Кто-нибудь знает, почему это может быть?

Это раздражает, когда я работаю с API-интерфейсами, которые не ясно, что именно они возвращают, поэтому я в конечном итоге if (someCollection != null) везде ...

Редактировать: Спасибо всем, кто объяснил, что foreach использует GetEnumerator и если нет перечислителя для получения, foreach потерпит неудачу. Наверное, я спрашиваю, почему язык / время выполнения не может или не будет выполнять нулевую проверку перед захватом перечислителя. Мне кажется, что поведение по-прежнему будет четко определено.


Ну, короткий ответ - «потому что именно так его разработали разработчики компилятора». Реально, однако, ваш объект коллекции является нулевым, поэтому компилятор не может заставить перечислитель перебирать коллекцию.

Если вам действительно нужно сделать что-то подобное, попробуйте нулевой оператор коалесценции:

    int[] array = null;

    foreach (int i in array ?? Enumerable.Empty<int>())
    {
        System.Console.WriteLine(string.Format("{0}", i));
    }

Потому что нулевая коллекция - это не то же самое, что пустая коллекция. Пустая коллекция - это объект коллекции без элементов; нулевой набор является несуществующим объектом.

Вот что попробовать: Объявите две коллекции любого рода. Инициализируйте его так, чтобы он был пуст, и назначьте другое значение null . Затем попробуйте добавить объект в обе коллекции и посмотреть, что произойдет.


Просто напишите метод расширения, чтобы помочь вам:

public static class Extensions
{
   public static void ForEachWithNull<T>(this IEnumerable<T> source, Action<T> action)
   {
      if(source == null)
      {
         return;
      }

      foreach(var item in source)
      {
         action(item);
      }
   }
}

Цикл foreach вызывает GetEnumerator .
Если коллекция имеет значение null , этот вызов метода приводит к NullReferenceException .

Плохая практика - вернуть null коллекцию; ваши методы должны возвращать пустую коллекцию.


Это вина Do.Something() . Лучшей практикой здесь было бы вернуть массив размера 0 (что возможно) вместо нуля.


Я думаю, что объяснение того, почему исключение выбрасывается, очень понятно с ответами, представленными здесь. Я просто хочу дополнить то, как я обычно работаю с этими коллекциями. Потому что, несколько раз, я использую коллекцию более одного раза и должен каждый раз проверять значение null. Чтобы этого избежать, я делаю следующее:

    var returnArray = DoSomething() ?? Enumerable.Empty<int>();

    foreach (int i in returnArray)
    {
        // do some more stuff
    }

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

Использование оператора нулевой проверки ?. также является отличным подходом. Но, в случае массивов (например, пример в вопросе), он должен быть преобразован в Список раньше:

    int[] returnArray = DoSomething();

    returnArray?.ToList().ForEach((i) =>
    {
        // do some more stuff
    });

SPListItem item;
DataRow dr = datatable.NewRow();

dr["ID"] = (!Object.Equals(item["ID"], null)) ? item["ID"].ToString() : string.Empty;




.net