双或三“;其中“;Linq中的子句

本文关键字:子句 Linq 其中 | 更新日期: 2023-09-27 17:50:41

代码:

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();

我用简单的数组进行了测试,结果表明它们是一样的。后者似乎做得更好。

双或三“;其中“;Linq中的子句

给定一个"标准"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");