Как работает LINQ внутри? - PullRequest
       17

Как работает LINQ внутри?

54 голосов
/ 22 марта 2009

Я люблю использовать LINQ в .net, но мне интересно узнать, как это работает внутри?

Кто-нибудь знает это?

Thks.

Ответы [ 5 ]

79 голосов
/ 22 марта 2009

Имеет смысл спросить о конкретном аспекте LINQ. Это немного похоже на вопрос «Как работает Windows» в противном случае.

Ключевые части LINQ для меня, с точки зрения C #:

  • Выражение деревьев. Это представления кода в виде данных. Например, дерево выражений может представлять понятие «взять строковый параметр, вызвать для него свойство Length и вернуть результат». Тот факт, что они существуют как data , а не как скомпилированный код, означает, что поставщики LINQ, такие как LINQ to SQL, могут анализировать их и преобразовывать в SQL.
  • Лямбда-выражения. Вот такие выражения:

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

    Лямбда-выражения преобразуются в делегаты или деревья выражений .

  • Анонимные типы. Вот такие выражения:

    new { X=10, Y=20 }
    

    Они по-прежнему статически типизированы, просто компилятор генерирует для вас неизменный тип со свойствами X и Y. Обычно они используются с var, что позволяет выводить тип локальной переменной из выражения инициализации.

  • Выражение запроса. Вот такие выражения:

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

    Они переводятся компилятором C # в "нормальный" C # 3.0 (то есть форму, которая не использует выражения запроса). После этого применяется разрешение перегрузки и т. Д., Что абсолютно необходимо для возможности использования одного и того же синтаксиса запроса с несколькими типами данных, при этом у компилятора нет знаний о таких типах, как Queryable. Вышеупомянутое выражение будет переведено на:

    people.Where(person => person.Age < 18)
          .Select(person => person.Name)
    
  • Методы расширения. Это статические методы, которые можно использовать так, как если бы они были методами экземпляра типа первого параметра. Например, такой метод расширения:

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

    затем можно использовать так:

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

    Обратите внимание, что реализация CountAsciiDigits использует другой метод расширения, Enumerable.Count().

Это большинство важных языковых аспектов. Затем есть реализации стандартных операторов запросов, в поставщиках LINQ, таких как LINQ to Objects, LINQ to SQL и т. Д. У меня есть представление о том, как достаточно просто реализовать LINQ to Objects - это на "Talks" страница сайта C # in Depth.

Обычно провайдеры, такие как LINQ to SQL, работают через класс Queryable. По своей сути они переводят деревья выражений в другие форматы запросов, а затем создают соответствующие объекты с результатами выполнения этих внепроцессных запросов.

Это охватывает все, что вас интересовало? Если есть что-то конкретное, о чем вы все еще хотите знать, просто отредактируйте свой вопрос, и я пойду.

5 голосов
/ 22 марта 2009

LINQ - это, в основном, комбинация отдельных особенностей C # 3.0:

  • вывод типа локальной переменной
  • свойства авто (не реализовано в VB 9.0)
  • методы расширения
  • лямбда-выражения
  • инициализаторы анонимного типа
  • понимание запросов

Для получения дополнительной информации о путешествии, чтобы добраться туда (LINQ), посмотрите это видео Андерса в LANGNET 2008:

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

4 голосов
/ 22 марта 2009

В простой форме компилятор берет ваш код-запрос и преобразует его в набор общих классов и вызовов. Ниже, в случае Linq2Sql, динамический SQL-запрос создается и выполняется с использованием DbCommand, DbDataReader и т. Д.

Скажем, у вас есть:

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

конвертируется в следующий код:

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

Много дженериков, огромные накладные расходы.

1 голос
/ 22 марта 2009

По сути, linq представляет собой смесь некоторых языковых возможностей (компилятор) и некоторых расширений фреймворка. Поэтому, когда вы пишете запросы linq, они выполняются с использованием соответствующих интерфейсов, таких как IQuerable. Также обратите внимание, что среда выполнения не играет роли в linq.

Но трудно судить о Линке в коротком ответе. Я рекомендую вам прочитать какую-нибудь книгу, чтобы в ней разобраться. Я не уверен насчет книги, в которой рассказывается о внутренностях Linq, но Linq в действии дает хорошее представление об этом.

0 голосов
/ 13 марта 2014

У меня есть небольшая программа на 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;
        }
    }
}

Используйте соответствующие точки останова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...