在什么时候确定LINQ数据源?

时间:2017-01-04 12:54:29

标签: c# linq ienumerable extension-methods

鉴于以下两个LINQ样本,在什么时候确定了LINQ数据源?

int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
IEnumerable<int> linqToOjects = numbers.Where(x => true);

XElement root = XElement.Load("PurchaseOrder.xml");
IEnumerable<XElement> linqToXML = root.Elements("Address").Where(x => true);

我的理解是用于查询这两个不同数据源的底层代码存在于LINQ方法生成的IEnumerable对象中。

我的问题是,在什么时候确定是否会生成使用Linq To Objects库或Linq To XML库的代码?

我认为用于查询这些数据源的底层代码(实际上用于查询数据的代码)存在于它们自己的库中,并且依赖于数据源进行调用。我查看https://referencesource.microsoft.com/来查看Where子句/扩展方法的代码,认为对所需提供程序的调用可能在那里,但它似乎是通用的。

如何确定进入IEnumerable的魔力?

2 个答案:

答案 0 :(得分:6)

&#34;数据源&#34;立即确定。例如,在您的第一个示例中,Where的返回值是一个实现IEnumerable<int>(特别是Enumerable.WhereArrayIterator<int>类)的对象,该对象依赖于numbers对象(存储为字段)。并且第二个示例中Where的返回值是一个可枚举的对象,它依赖于xml元素对象。因此,即使在开始枚举之前,结果可枚举也知道从哪里获取数据。

答案 1 :(得分:3)

  

我的问题是,在什么时候确定是否代码   将生成使用Linq To Objects库或Linq To   XML库?

我认为没有代码生成。 LINQ只使用数据源enumerator

您有一个实施IEnumerable

的班级
  

公开枚举器,它支持对a的简单迭代   指定类型的集合。

因此,您可以使用方法GetEnumerator

  

返回循环访问集合的枚举数。

所有LINQ都需要工作,enumerator

在您的示例中,您使用Where LINQ扩展方法来应用某些过滤器。

IEnumerable<T> Where(this IEnumerable<T> source, Func<T, bool> predicate)

在实施中我们需要:
- 获取枚举器(source.GetEnumerator())
- 遍历集合并应用过滤器(谓词)

Enumerable reference source中,您已经实现了方法Where。您可以看到他对数组(TSource [])和list(List)使用了一些特定的实现,但他对实现IEnumerable的所有其他类使用WhereEnumerableIterator。 所以没有代码生成,代码就在那里。

我认为您可以理解课程WhereEnumerableIterator的实施,您只需先了解如何实施IEnumerator

Here你可以看到MoveNext的实现。他们调用 source.GetEnumerator(),然后他们遍历集合( enumerator.MoveNext())并应用过滤器(谓词(项目))。

public override bool MoveNext() {
    switch (state) {
        case 1:
            enumerator = source.GetEnumerator();
            state = 2;
            goto case 2;
        case 2:
            while (enumerator.MoveNext()) {
                TSource item = enumerator.Current;
                if (predicate(item)) {
                    current = item;
                    return true;
                }
            }
            Dispose();
            break;
    }
    return false;
}  

XContainer.GetElement使用yield关键字返回IEnumerable。

  

在语句中使用yield关键字时,表示该   方法,运算符或获取它的访问器是迭代器。   使用yield来定义迭代器不需要显式   额外的类(保存枚举状态的类,请参阅   IEnumerator实例化IEnumerable和   用于自定义集合类型的IEnumerator模式。

由于yield关键字的神奇之处,我们可以获得一个IEnumerable,我们可以枚举该集合。这是LINQ唯一需要的东西。