[C#] 컬렉션이 null 일 때 .NET foreach 루프가 NullRefException을 발생시키는 이유는 무엇입니까?

그래서 나는 종종이 상황을 겪습니다 … 여기서 Do.Something(...)null 컬렉션을 반환합니다 :

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

그런 다음이 컬렉션을 다음과 같이 사용하려고합니다.

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

궁금합니다 .foreach 루프가 null 컬렉션에서 작동하지 않는 이유는 무엇입니까? 0 개의 반복이 null 컬렉션으로 실행되는 것이 논리적 인 것 같습니다 … 대신에 NullReferenceException. 왜 이것이 될 수 있는지 아는 사람이 있습니까?

반환하는 내용이 확실하지 않은 API로 작업하면서 짜증나는 일 이니 if (someCollection != null)어디에서나 끝납니다 …

편집 :foreach 사용법 을 설명해 주셔서 감사합니다 .GetEnumerator 얻을 열거자가 없으면 foreach가 실패합니다. 열거 형을 잡기 전에 언어 / 런타임이 null 검사를 수행 할 수없는 이유를 묻고있는 것 같습니다. 그 행동은 여전히 ​​잘 정의되어있는 것 같습니다.



답변

짧은 대답은 “컴파일러 디자이너가 설계 한 방식이기 때문입니다.” 그러나 실제로는 컬렉션 객체가 null이므로 컴파일러가 열거자를 통해 컬렉션을 반복 할 수있는 방법이 없습니다.

실제로 이와 같은 작업을 수행 해야하는 경우 null 병합 연산자를 사용해보십시오.

int[] array = null;

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


답변

foreach루프는 호출 GetEnumerator방법.
컬렉션이 null이면이 메서드 호출은을 발생 NullReferenceException시킵니다.

null컬렉션 을 반환하는 것은 좋지 않습니다 . 대신 메소드가 빈 컬렉션을 반환해야합니다.


답변

빈 컬렉션과 컬렉션에 대한 null 참조에는 큰 차이가 있습니다.

foreach내부적으로 를 사용 하면 IEnumerable의 GetEnumerator () 메서드 가 호출 됩니다. 참조가 null 인 경우,이 예외가 발생합니다.

그러나 빈 IEnumerable또는 을 갖는 것은 완벽하게 유효합니다 IEnumerable<T>. 이 경우, foreach는 컬렉션이 비어 있기 때문에 어떤 것에 대해서도 “반복”하지는 않지만 완벽하게 유효한 시나리오이기 때문에 던지지도 않습니다.


편집하다:

개인적 으로이 문제를 해결 해야하는 경우 확장 방법을 권장합니다.

public static IEnumerable<T> AsNotNull<T>(this IEnumerable<T> original)
{
     return original ?? Enumerable.Empty<T>();
}

그런 다음 전화하십시오.

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


답변

그것은 오래 전에 대답하고 있지만 null 포인터 예외를 피하기 위해 다음과 같은 방법 으로이 작업을 시도했지만 C # null check operator?를 사용하는 사람에게 유용 할 수 있습니다.

     //fragments is a list which can be null
     fragments?.ForEach((obj) =>
        {
            //do something with obj
        });


답변

이 문제를 해결하기위한 또 다른 확장 방법 :

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);
});


답변

확장 방법을 작성하면 도움이됩니다.

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);
      }
   }
}


답변

null 컬렉션은 빈 컬렉션과 같지 않기 때문입니다. 빈 컬렉션은 요소가없는 컬렉션 개체입니다. null 컬렉션은 존재하지 않는 개체입니다.

다음은 시도해 볼만한 사항입니다. 두 가지 컬렉션을 모두 선언하십시오. 비어 있도록 하나를 정상적으로 초기화하고 다른 하나에 값을 할당하십시오 null. 그런 다음 두 컬렉션 모두에 개체를 추가하고 어떻게되는지 확인하십시오.