2009-11-10 5 views
9

IEnumerable 확장 메소드 FirstOrDefault가 원했던대로 정확히 수행하지 않아 FirstOrValue를 만들었습니다. 이 문제를 해결하는 좋은 방법입니까 아니면 더 좋은 방법이 있습니까?FirstOrDefault에 다른 테이크 업

public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value) 
{ 
    T first = source.FirstOrDefault(predicate); 
    return Equals(first, default(T)) ? value : first; 
} 

답변

39

코드가 잘못되었습니다. 당신은 아마 모든 경우를 고려하지 않았습니다.

물론 코드가 올 때까지 올바른지 또는 잘못되었는지는 알 수 없습니다.

"FirstOrValue<T>은 T와 술어 및 T 값의 시퀀스를 취해 하나의 술어와 일치하는 시퀀스의 첫 번째 아이템을 반환하거나, 또는 하나의 라인 스펙을 작성하여 시작합니다. , 없다면, 명시된 가치. "

귀하의 시도가 실제로 해당 사양을 구현합니까? 확실히! 테스트 :

int x = FirstOrValue<int>(new[] { -2, 0, 1 }, y=>y*y==y, -1); 

이 경우 -1을 반환합니다. 명세에 따라 정답은 0입니다. 술어와 일치하는 첫 번째 항목은 0이므로 반환해야합니다.

public static T FirstOrValue<T>(this IEnumerable<T> sequence, Func<T, bool> predicate, T value) 
{ 
    if (sequence == null) throw new ArgumentNullException("sequence"); 
    if (predicate == null) throw new ArgumentNullException("predicate"); 
    foreach(T item in sequence) 
     if (predicate(item)) return item; 
    return value; 
} 

항상 먼저 스펙을 쓰기는 단지 하나의 문장의 경우에도 : 같은

사양의 올바른 구현을 보일 것이다.

+0

이것은 프레임 워크의 일부 여야합니다! 아니면 그것을 간과 했는가? – Marcel

+2

+1은 항상 "항상 spec을 작성하십시오". –

5

default(T) 참조 유형에 대해 기본적으로 null를 반환합니다.

난 당신이 DefaultIfEmpty를 사용하는 대신 가독성을 조정할하려면이

public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value) 
{ 
    T first = source.FirstOrDefault(predicate); 
    return first ?? value; 
} 
+4

난 그냥 한 줄에 그것을 쓸 것이다 : 반환 source.FirstOrDefault (술어) ?? 값; – Zote

+0

널 병합을위한 추가 포인트 –

+1

@zote : daniels 방법을 사용하면 디버거를 부착하고 진행중인 것을 확인할 수 있습니다. –

-1

나에게 합리적인 것 같다 할 것이다.

기본값을 만드는 것이 비용이 많이 드는 경우 람다를 사용하는 재정의를 만들 수도 있습니다 (필요한 경우에만 만듭니다).

public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, Func<T> getValue) 
{ 
    T first = source.FirstOrDefault(predicate); 
    return Equals(first, default(T)) ? getValue() : first; 
} 
+0

람다를 추가하면 매우 유용합니다. – Aurequi

0

과부하이기 때문에 술어가없는 버전을 언급 할 가치가 있습니다.

public static T FirstOrValue<T>(this IEnumerable<T> sequence, T value) 
{ 
    if (sequence == null) throw new ArgumentNullException("sequence"); 
    foreach(T item in sequence) 
     return item; 
    return value; 
} 
+2

시퀀스에 수천 개의 항목이 있고 Count 속성이 없다고 가정 해 보겠습니다. 당신은 * all *을 열거하여 * none *이 없음을 결정합니다. 항아리에 백만 페니가 있고 항아리가 비어 있는지 알고 싶다면 페니를 계산합니까? 이것은 당신이 여기서 사용하고있는 매우 나쁜 기법입니다. (정답이 정답 인 6 살짜리 질문에 대한 답변을 게시하는 이유가 분명하지 않고 원래 질문에 답변하지 않은 경우도 있는데, 다른 방법으로 추가 할 수 있습니다. 사이트에 더 많은 가치가 있습니까?) –

+0

나는 FirstOrValue를 찾고 당신의 사랑스러운 대답을 발견했습니다. 코드를 복사했는데 과부하가 발생했습니다. 다른 사람들이 같은 사고 과정을 겪었을 때를 대비하여 여기에 붙여 넣었습니다. 어쩌면 당신은 이것을 할 수있는 더 좋은 방법을 제안 할 수 있습니다. – djv

+1

자, 제안 된 메소드가 술어 없이는 쓴 것과 동일하기 때문에, 제 제안은 술어없이 동일한 메소드를 작성하는 것입니다 : public static T FirstOrValue (이 IEnumerable 시퀀스, T 값) { if (sequence == null) throw new ArgumentNullException ("sequence"); foreach (순서대로 T 항목) 반환 항목; 반환 값; }' –