[c#] foreach (항목의 T 항목) 전에 if (items! = null)이 불필요합니까?

나는 종종 다음과 같은 코드를 보게됩니다.

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

기본적으로 if조건은 null이 아닌 foreach경우에만 블록이 실행 되도록합니다 items. if조건이 정말로 필요한지 궁금 foreach합니다 items == null.

내 말은, 그냥 쓸 수 있을까요

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

itemsnull 인지 아닌지 걱정 하지 않고? 는 IS if조건 불필요한은? 아니면 이것은 유형 에 따라 달라 items지거나 어쩌면에 달려 T있습니까?



답변

(items! = null) 여부를 확인해야합니다. 그렇지 않으면 NullReferenceException이 발생합니다. 그러나 다음과 같이 할 수 있습니다.

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

하지만 성능을 확인할 수 있습니다. 그래서 나는 여전히 if (items! = null)을 먼저 갖는 것을 선호합니다.

Eric의 Lippert 제안에 따라 코드를 다음과 같이 변경했습니다.

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


답변

C # 6을 사용하면 새로운 null 조건 연산자를 List<T>.ForEach(Action<T>)(또는 자체 IEnumerable<T>.ForEach확장 메서드) 와 함께 사용할 수 있습니다 .

List<string> items = null;
items?.ForEach(item =>
{
    // ...
});


답변

여기서 진정한 의미 는 시퀀스가 ​​처음에는 거의 null이 될 수 없다는 것 입니다. 시퀀스가 있으면 절대 null이 아닌 모든 프로그램에서 불변으로 만드십시오. 항상 빈 시퀀스 또는 다른 정품 시퀀스로 초기화됩니다.

시퀀스가 null이 아닌 경우 분명히 확인할 필요가 없습니다.


답변

실제로 @Connect에 대한 기능 요청이 있습니다. http://connect.microsoft.com/VisualStudio/feedback/details/93497/foreach-should-check-for-null

그리고 응답은 매우 논리적입니다.

대부분의 foreach 루프는 null이 아닌 컬렉션을 반복 할 의도로 작성되었다고 생각합니다. null을 통해 반복을 시도하면 코드를 수정할 수 있도록 예외가 발생해야합니다.


답변

당신은 항상 null 목록으로 그것을 테스트 할 수 있습니다 …하지만 이것은 msdn 웹 사이트에서 찾은 것입니다.

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

식에 null 값이 있으면 System.NullReferenceException이 throw됩니다.


답변

슈퍼 플로 스가 아닙니다. 런타임시 항목은 IEnumerable로 캐스팅되고 해당 GetEnumerator 메서드가 호출됩니다. 그러면 실패 할 항목의 역 참조가 발생합니다.


답변

확장 메서드에서 null 검사를 캡슐화하고 람다를 사용할 수 있습니다.

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