2010-01-27 2 views
14

나는 FirstOrDefault와 관련하여 어느 것이 "모범 사례"로 간주되는지 약간 궁금합니다.FirstOrDefault()는 LINQ 대 FirstArDefault()를 Lambda와 함께 사용합니까?

나는 이미이 질문을 보았습니다.이 질문은 제가 가지고있는 질문과 비슷하지만 제 질문에 대한 답변에 충분히 가깝지 않습니다.

"더 나은 코드"중 어느 것입니까? 그리고 왜? IMO, 그것은 청소기 코드를 만들면서

var foos = GetMyEnumerableFoos(); 

var foo1 = (from f in foos 
    where f.Bar == "spider monkey" 
    select f).FirstOrDefault(); 

/* OR */ 

var foo2 = foos.FirstOrDefault(f => f.Bar == "spider monkey"); 

나는 후자쪽으로 경향이있다. 그러나 나는 그곳에서 벌어지는 일의 기술적 인 "용기"가 다른면에서보다 효율적인지 아닌지에 대해 궁금합니다. 다른 유형의 IEnumerables를 사용하는 경우이 변경됩니까? 같은 DataTables 또는 문자열 배열 또는 LINQ 개체?

========= 존 소총의 게시물 올바른 가정

, 내가 리플렉터에보고 갔다 편집 ==========는 어디서 FirstOrDefault 모양을 참조하고 (=> f.Bar f를 == "거미 원숭이") foos.Where의 경우

FirstOrDefault()

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 
{ 
    if (source == null) 
    { 
     throw Error.ArgumentNull("source"); 
    } 
    if (predicate == null) 
    { 
     throw Error.ArgumentNull("predicate"); 
    } 
    if (source is Iterator<TSource>) 
    { 
     return ((Iterator<TSource>) source).Where(predicate); 
    } 
    if (source is TSource[]) 
    { 
     return new WhereArrayIterator<TSource>((TSource[]) source, predicate); 
    } 
    if (source is List<TSource>) 
    { 
     return new WhereListIterator<TSource>((List<TSource>) source, predicate); 
    } 
    return new WhereEnumerableIterator<TSource>(source, predicate); 
} 

되는 공급 것이다 : 여기에 내가 생각 해낸거야. :

public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source) 
{ 
    if (source == null) 
    { 
     throw Error.ArgumentNull("source"); 
    } 
    IList<TSource> list = source as IList<TSource>; 
    if (list != null) 
    { 
     if (list.Count > 0) 
     { 
      return list[0]; 
     } 
    } 
    else 
    { 
     using (IEnumerator<TSource> enumerator = source.GetEnumerator()) 
     { 
      if (enumerator.MoveNext()) 
      { 
       return enumerator.Current; 
      } 
     } 
    } 
    return default(TSource); 
} 

foos.FirstOrDefault (f => f.Bar == "spider monkey")의 경우;

public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 
{ 
    if (source == null) 
    { 
     throw Error.ArgumentNull("source"); 
    } 
    if (predicate == null) 
    { 
     throw Error.ArgumentNull("predicate"); 
    } 
    foreach (TSource local in source) 
    { 
     if (predicate(local)) 
     { 
      return local; 
     } 
    } 
    return default(TSource); 
} 

것을 보면 아직도 나 효율성 특정 개체 유형에 대한 적절한 반복자를 사용하여이 추가됩니다 조금 혼란 잎? 아니면 모든 것을 건너 뛰고 루핑을 시작하고 테스트하는 것이 더 효율적입니까? 내 직감은 나에게 그것이 후자라고 다시 말합니다.

답변

17

음, "선택"부분은 어쨌든 컴파일러에 의해 제거됩니다, 그래서 당신은 정말 비교하고 있습니다 :

foo.Where(f => f.Bar == "spider monkey") 
    .FirstOrDefault() 

foo.FirstOrDefault(f => f.Bar == "spider monkey") 

대 내가 어떤 이 크게 만들 것입니다 의심은 LINQ에서 개체로의 효율성과 차이가 있습니다. 개인적으로 후자의 버전을 직접 사용하고 싶습니다 ... 다른 곳에서 쿼리의 필터링 부분을 재사용하고 싶지 않으면.

+0

재미 있습니다. 나는 당신이 언급 한 그 세 가지 방법으로 어떤 일이 벌어지고 있는지를보기 위해 당신이 게시물 인 후에 조금 더 파고 들었다. 나는 나의 발견을 위에 게시했다. .. 그것은 확실히 나의 질문에 답하는 것을 돕는다. –

+0

체크하지 않았지만'Where'' return's 결과가'IList'에 없다고 가정하기 때문에 두 개의 최종 루프는 사실상 동일합니다 :'MoveNext'는'Where ', FirstOrDefault (predicate) 호출이이를 명시 적으로 호출 할 때. 그러므로'Where' 버전은'false' (그리고'true'가 존재한다면)'술어'당 하나의 추가 호출을합니다. –

4

더 간단하기 때문에 후자를 선호합니다.

효율성면에서 나는 당신이 2의 실질적인 차이점을 발견 할 수 있을지 의심 스럽습니다. 실제로는 약간 다르지만 실제로는 행동이 동일합니다.

가장 큰 차이점은 첫 번째 요소가 새로운 IEnumerable<T> 인스턴스를 생성하고 첫 번째 요소에 대해 걸었다는 것입니다. 후자의 경우 기존 IEnumerable<T> 인스턴스는 술어와 일치하는 첫 번째 값으로 이동합니다. 다시 한 번 눈치 채지 못할 것입니다.

-1

두 번째 버전이 훨씬 더 효율적입니다.

첫 번째 버전

var foo1 = (from f in foos 
    where f.Bar == "spider monkey" 
    select f).FirstOrDefault(); 

모든 항목을 항상 루프, 일치하는 항목의 새 컬렉션을 생성.

var foo2 = foos.FirstOrDefault(f => f.Bar == "spider monkey"); 

가 일치하는 다음 항목을 통해서만 루프 발견되는 것까지 두 번째 버전이 돌아왔다.

+3

사실 LINQ에 중단 점을 넣으면이 내용이 표시되지만 LINQ 문은 한 번만 실행됩니다. 심지어 LINQ 문을 광고 nauseum에 의해 생성 된 IEnumerables에 액세스하는 LINQ 문을 가질 수 있으며 FirstOrDefault를 호출하면 각 문항을 한 번만 통과하게됩니다. 그래도 걱정하지 않아도 나는 똑같은 생각을하고있었습니다. ;) –

+1

두 항목에서 "항상 일치하는 항목의 새 모음을 만드는 모든 항목을 반복합니다."라는 문장은 false입니다. 먼저 '거미 원숭이'가 없다면'foos'의 모든 항목을 반복합니다. 그렇지 않으면 첫 번째 "거미 원숭이"를 때릴 것입니다. 두 번째로 일치하는 항목의 모음을 만들지 않고 _first_1을 반환합니다. –

+2

@phdesign은 괄호의 존재 때문에 혼란 스러웠다 고 생각합니다. 내부에서 모든 것이 먼저 실행된다고 가정했기 때문입니다 (괄호는 일반적으로 그렇게하기 때문에). 그러나이 규칙은이 경우 적용되지 않으며 그룹화 구성으로 만 존재합니다. –