2017-01-04 10 views
3

Учитывая приведенные ниже два примера LINQ, в какой точке определяется источник данных 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); 

Я понимаю, что базовый код, используемый для запроса этих двух различных источников данных живет в пределах IEnumerable объекта, полученного с помощью методов LINQ.

Мой вопрос в том, в какой именно момент определяется, будет ли генерироваться код для использования библиотеки Linq To Objects или библиотеки Linq To XML?

Я бы предположил, что базовый код (код, который фактически выполняет работу с запросом данных), используемый для запроса этих источников данных, существует в своих собственных библиотеках и вызван в зависимости от источника данных. Я просмотрел https://referencesource.microsoft.com/, чтобы посмотреть на код метода Where/extension, предполагающего, что вызов нужного провайдера может быть там, но он, как представляется, является общим.

Как определяется магия, которая входит в IEnumerable?

+0

'IEnumerable' не определяется до тех пор, пока не изменится на« определенный »тип, например, когда вы вызываете' .ToList() 'или' .ToArray() 'на нем. Но сам 'IEnumerable' никогда не определяется. – Franck

+0

Спасибо - я должен был назвать его экземпляром IEnumerable. – Brummy

+2

Единственный раз, когда этот вопрос имеет значение, когда вы работаете с IQueryable. В противном случае это не все довольно много linq для объектов. (Но фактическое внедрение, которое используется, выбирается во время компиляции, основываясь на том, какие классы вы предоставляете в качестве входных данных и какие методы расширения разрешены.) –

ответ

6

«Источник данных» определяется немедленно. Например, в вашем первом примере возвращаемое значение Where является объектом, который реализует IEnumerable<int> (в частности, класс Enumerable.WhereArrayIterator<int>), который имеет зависимость от объекта numbers (хранится как поле). И возвращаемое значение Where во втором примере является перечислимым объектом, который имеет зависимость от объекта элемента xml. Таким образом, даже до того, как вы начнете перечисление, получившийся перечислимый знает, откуда взять данные.

+0

Когда вы говорите, что в результате перечисляемый знает, где получить данные from_, знает ли он также ** как ** получить данные в этой точке, как в коде внутри перечисляемого, используемого для фактического запроса данных (сохраненных как поле), потому что я предполагаю, что объекты, используемые для запроса массива и объекта xml, сильно отличаются. – Brummy

+3

@Brummy Это не * нужно * знать как. Ответственность этого источника данных лежит на том, чтобы выставлять свои данные с помощью интерфейса «IEnumerable», поэтому весь метод «Where» должен использовать этот интерфейс и позволить базовому источнику данных делать все, что ему нужно, чтобы получить данные , – Servy

3

Мой вопрос, в какой момент именно она определяется, будет ли генерироваться использовать библиотеку Linq To Objects или Linq To библиотеки XML-код ?

Я думаю, что нет генерации кода. LINQ использует только источник данных enumerator.

У вас есть класс, которые реализуют IEnumerable

разоблачает нумератор, который поддерживает простую итерацию над сбором определенного типа.

Таким образом, вы можете использовать метод GetEnumerator.

Возвращает перечислитель, который выполняет итерацию через коллекцию.

И все это LINQ должно работать, enumerator.

В вашем примере вы используете метод расширения Where LINQ для применения некоторого фильтра.

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

В реализации мы должны:
- получить перечислитель (источник.GetEnumerator())
- перебирать коллекции и примените фильтр (предикат)

В Enumerable reference source у вас есть реализация метода Where. Вы можете видеть, что он использует определенную реализацию для массива (TSource []) и list (List), но он использует WhereEnumerableIterator для всех других классов, которые реализуют IEnumerable. Так что нет кода генерации, код есть.

Я думаю, вы можете понять реализацию класса WhereEnumerableIterator, вам нужно только сначала понять, как реализовать IEnumerator.

Here вы можете увидеть реализацию MoveNext. Они называют source.GetEnumerator(), а затем они перебирают по коллекции (enumerator.MoveNext()) и применяют фильтр (предикат (item)).

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 возвращает IEnumerable, используя ключевое слово yield.

При использовании ключевого слова выход в заявлении вы указываете, что метод, оператор, или получить сбруя, в котором он появляется итератор. Использование урожая для определения итератора устраняет необходимость в дополнительном классе (класс, который содержит состояние для перечисления, см. В примере IEnumerator), когда вы реализуете шаблон IEnumerable и IEnumerator для пользовательского типа коллекции.

Благодаря магии ключевого слова yield мы можем получить IEnumerable, и мы можем перечислить коллекцию. И это единственное, что нужно LINQ.

+0

Спасибо за подробный ответ, я просто смотрел на этот исходный код! Правильно ли я считаю, что объект, возвращенный методом 'GetElement' (' XContainer'), должен иметь метод GetEnumerator? Просматривая код ссылки Microsoft, я не вижу его. – Brummy

+0

Я вижу вашу точку сейчас. Объект, возвращаемый методом XContainer.GetElement, является IEnumerable , поэтому мы можем сделать: root.Elements («Address»). GetEnumerator(). И LINQ использует этот счетчик. Но как метод GetElement возвращает IEnumerable? Использование ключевого слова yield. Я изменил свой ответ, чтобы показать вам. –

 Смежные вопросы

  • Нет связанных вопросов^_^