2009-11-10 45 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