2017-01-04 8 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); 

나의 이해는이 두 개의 서로 다른 데이터 소스를 조회하는 데 사용되는 기본 코드는 LINQ 방법에 의해 생성 된 IEnumerable을 객체 내에 살고 있다는 것입니다.

제 질문은 어떤 시점에서 정확히 Linq 개체 라이브러리 또는 Linq To XML 라이브러리를 사용하도록 코드를 생성할지 여부를 결정합니다.

이러한 데이터 원본을 쿼리하는 데 사용되는 기본 코드 (실제로 데이터를 쿼리하는 코드)는 자체 라이브러리 내에 존재하며 데이터 원본에 의존하여 호출되는 것으로 가정합니다. https://referencesource.microsoft.com/에서 Where 절/확장 메서드의 코드를보고 원하는 공급자에 대한 호출이있을 수 있다고 생각했지만 일반적인 것 같습니다.

IEnumerable에 들어가는 마법은 어떻게 결정됩니까?

+0

'IEnumerable'은'.ToList()'또는'.ToArray()'를 호출 할 때와 같이 "결정된"타입으로 변경 될 때까지 결정되지 않습니다. 그러나 IEnumerable 자체는 절대로 결정되지 않습니다. – Franck

+0

감사합니다 - IEnumerable 인스턴스로 지정해야합니다. – Brummy

+2

IQueryable로 작업하는 경우에만이 문제가 중요합니다. 그렇지 않으면 개체에 거의 모든 linq되지 않습니다. (그러나 실제로 사용 된 임 플리 멘 테이션은 어떤 클래스를 입력으로 제공하고 어떤 확장 메소드가 해결되는지에 따라 컴파일 타임에 선택됩니다.) –

답변

6

"데이터 원본"이 즉시 결정됩니다. 예를 들어 첫 번째 예에서 Where의 반환 값은 numbers 개체 (필드로 저장 됨)에 대한 종속성이있는 IEnumerable<int> (특히 클래스는 Enumerable.WhereArrayIterator<int>)을 구현하는 개체입니다. 두 번째 예제에서 반환 값 Where은 xml 요소 개체에 대한 종속성이있는 열거 가능한 개체입니다. 그래서 여러분이 열거하기 시작하기 전에, 결과로 나오는 열거자는 어디에서 데이터를 가져올지를 안다.

+0

결과로 나온 열거 형은 from_ 데이터를 가져올 위치를 알고 있다고 말하면서도 ** 알고 있습니다. 어떻게 ** 그 시점에서 데이터를 얻으려면 열거 형 내의 코드 (실제로는 필드로 저장 됨)에서 배열 및 XML 객체를 쿼리하는 데 사용 된 기능이 매우 다르다고 생각하기 때문에 실제로 데이터를 쿼리하는 데 사용됩니다. – Brummy

+3

@Brummy 방법을 알 필요가 없습니다. 그 데이터 소스는'IEnumerable' 인터페이스를 사용하여 데이터를 공개해야하므로'Where' 메소드는 해당 인터페이스를 사용하고 기본 데이터 소스가 데이터를 가져 오기 위해 필요한 모든 작업을 수행 할 수 있도록해야합니다. . – Servy

3

내 질문에 정확하게 코드 는 Linq에에이 개체 라이브러리 또는 XML 라이브러리에 Linq에를 사용하여 생성됩니다 여부가 결정된다 어느 시점에서인가?

코드 생성이 없다고 생각합니다. LINQ는 데이터 소스 enumerator을 사용합니다.

당신은

IEnumerable가 지정된 형식의 콜렉션 단순 반복을 지원하는 열거를 공개합니다 구현 클래스가 있습니다.

따라서 GetEnumerator 메서드를 사용할 수 있습니다.

컬렉션을 반복하는 열거자를 반환합니다.

그리고이 모든 LINQ가 작동해야합니다 (enumerator).

예제에서는 Where LINQ 확장 메서드를 사용하여 일부 필터를 적용합니다. 구현에

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

우리가 필요로 :
- 열거 (소스를 얻을.GetEnumerator를은())
는 - 컬렉션을 반복하고에서 필터 (술어)

을 적용 Enumerable reference source 당신은 어디 방법의 구현이있다. 배열 (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.GetElementyield 키워드를 사용하여는 IEnumerable을 반환합니다.

문에서 yield 키워드를 사용하면 나타나는 메서드, 연산자 또는 get 접근자가 반복기임을 나타냅니다. yield를 사용하여 반복기를 정의하면 사용자 지정 컬렉션 형식에 IEnumerable 및 IEnumerator 패턴을 구현할 때 명시적인 추가 클래스 (열거 형의 상태를 보유하는 클래스, 예를 들어 IEnumerator 참조)가 필요하지 않습니다.

yield 키워드의 마법 덕분에 IEnumerable을 얻을 수 있으며 컬렉션을 열거 할 수 있습니다. 그리고 이것이 LINQ가 필요로하는 유일한 것입니다.

+0

자세한 답장을 보내 주셔서 감사합니다. 나는 그 소스 코드를보고있었습니다. 'GetElement' 메소드 ('XContainer')에서 반환 된 객체가 GetEnumerator 메소드를 가져야한다고 생각합니까? Microsoft 참조 코드를 살펴보면 볼 수 없습니다. – Brummy

+0

지금 당신의 요지를 봅니다. XContainer.GetElement 메서드에서 반환하는 개체는 IEnumerable 이므로 다음과 같이 할 수 있습니다. root.Elements ("Address"). GetEnumerator(). 그리고 LINQ는이 열거자를 사용합니다. 그러나 GetElement 메서드가 IEnumerable을 반환하는 방법은 무엇입니까? yield 키워드 사용. 나는 당신에게 보여줄 나의 대답을 수정했다. –