2009-03-22 16 views
49

.net에서 LINQ를 사용하는 것을 좋아하지만 내부적으로 어떻게 작동하는지 궁금합니다.LINQ는 내부적으로 어떻게 작동합니까?

아무도 알고 있나요?

Thks.

+6

John Skeet의 책 C#을 깊이 구입하여보십시오. –

+0

간단히 말해 C# 3.0도 좋습니다. –

+1

[Linq in Action] [1]의 3 분의 1을 읽었으며 훌륭한 책입니다. [1] : http://www.manning.com/marguerie/ –

답변

76

. Windows가 어떻게 작동하는지 묻는 것과 조금 다릅니다. LINQ의

의 핵심 부분은 C#을 관점에서, 나를위한 것입니다 :

  • 표현 나무. 이것들은 코드를 데이터로 표현한 것입니다. 예를 들어 표현식 트리는 "문자열 매개 변수를 가져 와서 Length 속성을 호출하고 결과를 반환합니다"라는 개념을 나타낼 수 있습니다. 컴파일 된 코드가 아닌 데이터이라는 사실은 LINQ to SQL과 같은 LINQ 공급자가이를 분석하여 SQL로 변환 할 수 있음을 의미합니다.
  • 람다 식.이들은 다음과 같이 표현된다 :

    x => x * 2 
    (int x, int y) => x * y 
    () => { Console.WriteLine("Block"); Console.WriteLine("Lambda"); } 
    

    람다 표현식은 대표 또는 식 트리에 하나 변환됩니다.

  • 익명 유형. 이들은 다음과 같이 표현된다 :

    이 여전히 정적으로 입력된다
    new { X=10, Y=20 } 
    

    , 그냥 컴파일러 속성 XY와 함께 당신을 위해 불변의 유형을 생성합니다. 이것들은 대개 var과 함께 사용되어 지역 변수의 유형을 초기화 표현식에서 추론 할 수 있습니다.

  • 쿼리 식. 이들은 다음과 같이 표현된다 :

    from person in people 
    where person.Age < 18 
    select person.Name 
    

    는 이들은 "정상적인"C# 3.0 (쿼리 표현식을 사용하지 않는 즉, 형태)로 C# 컴파일러에 의해 변환됩니다. 과부하 해결 (overload resolution) 등은 이후에 적용되며, 이는 Queryable과 같은 유형에 대한 지식이없는 컴파일러없이 여러 데이터 유형에 대해 동일한 쿼리 구문을 사용할 수 있다는 점에서 절대적으로 중요합니다. 위의 표현식은 다음과 같이 번역됩니다.

    확장 메소드. 이들은 마치 첫 번째 매개 변수 유형의 인스턴스 메소드 인 것처럼 사용할 수있는 정적 메서드입니다. 예를 들어, 이와 같은 확장 방법 :

    public static int CountAsciiDigits(this string text) 
    { 
        return text.Count(letter => letter >= '0' && letter <= '9'); 
    } 
    

    다음과 같이 사용될 수있다 : CountAsciiDigits의 구현은 다른 확장 방법을 사용 Enumerable.Count()

    string foo = "123abc456"; 
    int count = foo.CountAsciiDigits(); 
    

    참고있다. 관련 언어 측면의 대부분의

. 그런 다음 표준 쿼리 연산자의 구현, LINQ 및 LINQ to SQL 및 LINQ to SQL 등의 LINQ 공급자에 대한 구현이 있습니다. 개체에 LINQ를 구현하는 방법이 합리적으로 간단한 방법에 대한 프레젠테이션이 있습니다. C#의 "Talks" 페이지에 있습니다. 웹 사이트.

LINQ에서 SQL 로의 작업과 같은 공급자는 일반적으로 Queryable 클래스를 통해 이루어집니다. 핵심에서는 표현식 트리를 다른 쿼리 형식으로 변환 한 다음 해당 out-of-process 쿼리를 실행 한 결과와 함께 적절한 개체를 생성합니다.

관심있는 모든 것을 다루고 있습니까? 특히 당신이 알고 싶은 것이 있다면 그냥 질문을 편집하면됩니다.

+0

@JonSkeet linq을 가능케하는 핵심 요소에 제네릭을 추가 할 것입니다. – nawfal

+0

@nawfal : 이미 "익명 유형"아래에'var '이 있습니다. 제네릭이 필요하지만, 그들은 이미 C# 2의 일부 였고 LINQ 외부에서 널리 사용되었습니다. 필요한 모든 것을 * 열거하면 "속성 액세스"와 "변수"등을 포함해야합니다. –

+0

@JonSkeet'var'은 익명 형식을 벗어난 언급입니다. IOrderedEnumerable 등을 쓰고, 비슷한 유추를합니다. 흠, 개인적으로 제네릭은 비록 linq, ymmv에서 유틸리티에 관해서는 재산 접근과 조금 다르다고 생각합니다. – nawfal

1

기본적으로 linq은 일부 언어 기능 (컴파일러)과 일부 프레임 워크 확장을 혼합 한 것입니다. 그래서 linq 쿼리를 작성하면 IQuerable과 같은 적절한 인터페이스를 사용하여 실행됩니다. 또한 런타임은 linq에서 아무런 역할을하지 않습니다.

그러나 짧은 답변에서는 linq에게 정의를 적용하기가 어렵습니다. 나는 당신 자신을 얻기 위해 어떤 책을 읽을 것을 권한다. 나는 Linq의 내부를 말하는 책에 대해 확신하지 못하지만, Linq in Action은 그것에 대해 좋은 손을 준다.

4

간단한 형태로 컴파일러는 코드 쿼리를 가져 와서 일련의 일반 클래스 및 호출로 변환합니다. 밑에, Linq2Sql의 경우, 동적 SQL 쿼리 DbCommand를 사용하여 구성되고 실행됩니다, DbDataReader에서 등

은 당신이 말 :

IQueryable<tbl_dir_office> q = 
    dc.mytable.Select<tbl_dir_office, tbl_dir_office>(
     Expression.Lambda<Func<mytable, mytable>>(
      exp = Expression.Parameter(typeof(mytable), "x"), 
      new ParameterExpression[] { exp } 
     ) 
    ); 

:

var q = from x in dc.mytable select x; 

가 다음 코드로 변환됩니다 제네릭이 많고 엄청난 오버 헤드가 있습니다.

+1

거대한 오버 헤드? 너 무슨 뜻이야? –

+0

약을 선택하면 공급자 초기화 메서드, 연결 확인, 트랜잭션 확인, 매개 변수 컬렉션 초기화, 독자 호출, 결과 번역, 수천 개의 구문 분석 등의 실행 메서드가 호출됩니다. – Ruslan

+2

@Ruslan, 당신이 언급 한 거의 모든 것들은 오버 헤드로 간주되지 않으며, 게다가 트랜잭션이 첨부되어 있는지 확인하는 것과 같이 DB에서 명령을 실행하는 것에 비해 비용이 매우 적습니다. –

4

LINQ 기본적 이들 C# 3.0 이산 기능의 조합 :

  • 로컬 변수 타입 추론
  • 자동 등록 (VB 9.0에서 구현되지 않음)
  • 확장 방법
  • 람다 식
  • 익명 형식 초기화 도구
  • 쿼리 이해

가 얻을 수있는 여행에 대한 자세한 내용은 (LINQ)의 경우, LANGNET 2008 년 앤더스의 동영상을 참조 : 그것은 LINQ의 특정 측면에 대해 물어 더 의미가

http://download.microsoft.com/download/c/e/5/ce5434ca-4f54-42b1-81ea-7f5a72f3b1dd/1-01%20-%20CSharp3%20-%20Anders%20Hejlsberg.wmv

+2

자동 속성은 LINQ에서 역할을 수행하지 않으며 VB9에 없습니다. –

+0

예, 맞습니다. VB 9.0에는 없습니다. 내 대답을 편집 할게. –

+1

자동 속성이 LINQ와 아무 관련이 없다는 요점을 놓쳤다 고 생각합니다. –

0

저는 C#에서 LINQ 구현을 보여주는 작은 C# 프로그램이 있습니다.

class Program 
{ 
    static void Main(string[] args) 
    { 
     //Eventhough we call the method here, it gets called ONLY when the for loop is executed 
     var Cities = LinQFunction(new List<string>() { "Bangalore", "Mysore", "Coorg", "Tumkur", "Kerala", "TamilNadu" }); 

     //LinQFunction() gets callled now 
     foreach(var city in Cities) 
     { 
      Console.WriteLine(city); 
     } 
    } 

    //This function is called ONLY when the foreach loop iterates and gets the item from the collection 
    static IEnumerable<string> LinQFunction(List<string> cities) 
    { 
     foreach (var item in cities) 
     { 
      //Return each 'item' at a time 
      yield return item; 
     } 
    } 
} 

적절한 중단 점을 사용하십시오.

관련 문제