2009-11-10 86 views
9

IEnumerable擴展方法FirstOrDefault沒有完全按照我想要的方式做,所以我創建了FirstOrValue。這是一個很好的方式去解決這個問題,還是有更好的方法?FirstOrDefault不同的採取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.匹配謂詞的第一個項目是零,因此應該返回。

正確實現的規範的會是什麼樣子:

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 2011-09-13 12:54:17

+2

+1「總是先寫規格」。 – 2012-02-20 07:00:29

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

我只是把它寫在一行上: return source.FirstOrDefault(predicate)??值; – Zote 2009-11-10 15:40:47

+0

無效合併加分 – 2009-11-10 15:41:25

+1

@zote:做到這一點丹尼爾斯的方式可以更容易地附加一個調試器,看看發生了什麼 – 2009-11-10 15:41:59

-1

似乎是合理的我。

如果缺省值的創建很昂貴,只在必要時創建它,您也可以創建使用lambda的覆蓋。

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

非常好,添加一個lambda使它更加有用。 – Aurequi 2009-11-10 15:55:13

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屬性。你會列舉其中的所有*,以確定它們中沒有*沒有*。如果你在罐子裏有一百萬便士,並且你想知道這個罐子是否是空的,你會數錢嗎?這是你在這裏使用的非常非常糟糕的技術。 (我也不清楚爲什麼你發佈了一個已經接受了正確答案的六年前問題的答案,實際上甚至沒有回答原始問題;也許還有一些其他方法可以添加更有價值的網站?) – 2015-04-27 18:50:44

+0

我正在尋找FirstOrValue並遇到了你可愛的答案。我複製了你的代碼,並且發生在我身上的是過載。如果其他人經歷了相同的思考過程,請粘貼此處。也許你可以建議一個更好的方法來做到這一點。 – djv 2015-04-27 20:44:09

+1

那麼,既然你提出的方法與我所寫的方法相同,除了沒有謂詞,我的建議是編寫沒有謂詞的同樣的方法:'public static T FirstOrValue (這個IEnumerable 序列,T值){ 如果(sequence == null)拋出新的ArgumentNullException(「sequence」); foreach(T按順序排列) return item; 返回值; }' – 2015-04-27 21:15:43