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


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

кто-нибудь знает что?

Thks.

5 54

5 ответов:

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

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

  • выражение деревьев. Это представления кода как данных. Например, дерево выражений может представлять понятие "взять строковый параметр, вызвать свойство Length на нем и вернуть результат". Дело в том, что они существуют как сведения а чем как скомпилированный код означает, что поставщики 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 для объектов - это на "переговоры" страница C# в глубину вебсайт.

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

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

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

в простой форме, компилятор принимает код-запрос и преобразует его в кучу универсальных классов и вызовов. Ниже, в случае 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 }
        )
    );

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

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

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

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

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