您的位置:首页 > 其它

Linq扩展方法获取单个元素

2015-09-11 17:20 477 查看
在使用Linq 提供的扩展方法时,First(OrDefault), Single(OrDefault), Last(OrDefault)都具有返回单个元素的功能。MSDN对这些方法的描述只有功能说明,没有关于内部的相关实现的描述说明。

首先我们来看下MSDN上关于这些扩展方法的官方描述:

First: 返回序列中的第一个元素 。

FirstOrDefault: 返回序列中的第一个元素;如果未找到元素,则返回默认值。

Last:返回序列的最后一个元素。

LastOrDefault: 返回序列中的最后一个元素;如果未找到元素,则返回默认值。

Single: 返回序列的唯一元素;如果该序列并非恰好包含一个元素,则会引发异常。

SingleOrDefault:返回序列中的唯一元素;如果该序列为空,则返回默认值;如果该序列包含多个元素,此方法将引发异常。

这些方法功能类似,如果不仔细阅读说明,细细推敲,在实际运用中很容易造成误用,从而导致性能的损失。

为了彻底分清这些方法的区别,我们用代码来验证不同方法的执行结果。代码如下:

public static TSource First<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 element in source)
{
if (predicate(element)) return element;
}
throw Error.NoMatch();
}

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 element in source)
{
if (predicate(element)) return element;
}
return default(TSource);
}

public static TSource Last<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
TSource result = default(TSource);
bool found = false;
foreach (TSource element in source)
{
if (predicate(element))
{
result = element;
found = true;
}
}
if (found) return result;
throw Error.NoMatch();
}

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

public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
TSource result = default(TSource);
long count = 0;
foreach (TSource element in source)
{
if (predicate(element))
{
result = element;
checked { count++; }
}
}
switch (count)
{
case 0: throw Error.NoMatch();
case 1: return result;
}
throw Error.MoreThanOneMatch();
}

public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
TSource result = default(TSource);
long count = 0;
foreach (TSource element in source)
{
if (predicate(element))
{
result = element;
checked { count++; }
}
}
switch (count)
{
case 0: return default(TSource);
case 1: return result;
}
throw Error.MoreThanOneMatch();
}


View Code
从上面的代码我们可以看到,所有方法的查找都是顺序查找,First(OrDefault)在查找时,当查找到满足条件的元素时会返回第一个元素。Single(OrDefault)和Last(OrDefault)在查找时,无论查找是否满足条件都会遍历整个集合;Single(OrDefault)在遍历时会对匹配的结果进行计数,用于判断结果是否唯一。带有OrDefault的方法在没有查找到指定条件时,会返回一个默认值default(TSource);与之对应的是无OrDefault的方法在遍历完集合都没有找到满足条件的元素时会抛出InvalidOperationException异常。

扩展方法条件匹配(所有元素唯一)条件匹配(集合中元素有重复)条件不匹配查找次数
First返回匹配的元素返回匹配的元素抛出InvalidOperationException1-N
FirstOrDefault返回匹配的元素返回匹配的元素返回default(TSource)1-N
Single返回匹配的元素唯一匹配时返回该元素,多个匹配时抛出InvalidOperationException抛出InvalidOperationExceptionN
SingleOrDefault返回匹配的元素唯一匹配时返回该元素,多个匹配时抛出InvalidOperationException返回default(TSource)N
Last返回匹配的元素返回匹配的元素抛出InvalidOperationExceptionN
LastOrDefault返回匹配的元素返回匹配的元素返回default(TSource)N
相关资料
https://msdn.microsoft.com/zh-cn/library/vstudio/system.linq.enumerable_methods%28v=vs.100%29.aspx http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: