代码:
var list=GetList()
.where(x=>x.att01=="X")
.where(x=>x.att02=="Y")
.where(x=>x.att03=="Z")
.SingleOrDefault();
这真的等于吗
var list=GetList()
.where(x=>x.att01=="X" && x.att02=="Y" && x.att03=="Z")
.SingleOrDefault();
我用简单的数组进行了测试,结果表明它们是一样的。后者似乎做得更好。
给定一个"标准"Enumerable.Where
,它们是完全等价的(从结果的角度来看(。第一个将由私有类WhereEnumerableIterator<TSource>
转换为第二个,确切地说,通过以下方法:
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) {
return new WhereEnumerableIterator<TSource>(source, CombinePredicates(this.predicate, predicate));
}
将以这种方式组合谓词:
static Func<TSource, bool> CombinePredicates<TSource>(Func<TSource, bool> predicate1, Func<TSource, bool> predicate2) {
return x => predicate1(x) && predicate2(x);
}
参见x => predicate1(x) && predicate2(x)
?
从技术上讲,第二个会快一点,因为第一个会有更多的委托调用要做,但除非您要过滤数百万行,否则时间差可以忽略不计。
注意,虽然Enumerable.Where
有一些有趣的技巧,但即使是非智能的.Where
,比如:
public static class SimpleEnumerable
{
public static IEnumerable<TSource> SimpleWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource element in source)
{
if (predicate(element))
{
yield return element;
}
}
}
}
将完全等效(但更慢!(。请参阅此处的示例:https://ideone.com/QAQZ65
我用简单的数组进行了测试,结果表明它们是一样的。
从语义上讲,它们都是一样的在这种特殊情况下(使用当前过载(,在幕后,WhereEnumerableIterator<TSource>
将输出一个带有链式谓词的枚举器:
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
// This is the important line
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);
}
IEnumerable<TSource>
实际上是由Where
调用提供的先前WhereEnumerableIterator<TSource>
。最终,它将合并谓词:
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate)
{
return new WhereEnumerableIterator<TSource>(source,
CombinePredicates(this.predicate,
predicate));
}
static Func<TSource, bool> CombinePredicates<TSource>(Func<TSource, bool> predicate1,
Func<TSource, bool> predicate2)
{
return x => predicate1(x) && predicate2(x);
}
但是,SingleOrDefault
本身具有占用Func<TSource, bool>
的过载,这将完全消除调用Where
的需要:
var list = GetList().SingleOrDefault(x => x.att01 == "X" &&
x.att02 == "Y" &&
x.att03 == "z");