64 votes

Comment fonctionne LINQ en interne ?

J'adore utiliser LINQ dans .NET, mais je veux savoir comment cela fonctionne en interne ?

8 votes

Envisagez d'acheter le livre C# in depth de John Skeet

1 votes

C# 3.0 in a nutshell est également bon.

2 votes

J'ai lu un tiers de [Linq in Action][1] et c'est un excellent livre. [1] : manning.com/marguerie

89voto

Jon Skeet Points 692016

Il est plus logique de poser des questions sur un aspect particulier de LINQ. C'est un peu comme demander "Comment fonctionne Windows" autrement.

Les parties clés de LINQ sont pour moi, d'un point de vue C# :

  • Arbres d'expression. Il s'agit de représentations du code en tant que données. Par exemple, un arbre d'expression pourrait représenter la notion de "prendre un paramètre de type chaîne de caractères, appeler la propriété Length sur celui-ci, et renvoyer le résultat". Le fait qu'ils existent en tant que données plutôt que sous forme de code compilé signifie que les fournisseurs LINQ tels que LINQ to SQL peuvent les analyser et les convertir en SQL.

  • Les expressions lambda. Ce sont des expressions comme celle-ci :

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

    Les expressions lambda sont converties soit en délégués o arbres d'expression .

  • Types anonymes. Il s'agit d'expressions comme celle-ci :

    new { X=10, Y=20 }

    Ils sont toujours typés statiquement, c'est juste que le compilateur génère un type immuable pour vous avec des propriétés. X y Y . Ils sont généralement utilisés avec var qui permet de déduire le type d'une variable locale à partir de son expression d'initialisation.

  • Expressions de requêtes. Ce sont des expressions comme celle-ci :

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

    Ceux-ci sont traduits par le compilateur C# en C# 3.0 "normal" (c'est-à-dire un formulaire qui n'utilise pas d'expressions de requête). La résolution des surcharges, etc., est appliquée ensuite, ce qui est absolument essentiel pour pouvoir utiliser la même syntaxe de requête avec plusieurs types de données, sans que le compilateur ait la moindre connaissance de types tels que Queryable. L'expression ci-dessus serait traduite en :

    people.Where(person => person.Age < 18)
          .Select(person => person.Name)
  • Méthodes d'extension. Il s'agit de méthodes statiques qui peuvent être utilisées comme s'il s'agissait de méthodes d'instance du type du premier paramètre. Par exemple, une méthode d'extension comme celle-ci :

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

    peut alors être utilisé comme ceci :

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

    Notez que l'implémentation de CountAsciiDigits utilise une autre méthode d'extension, Enumerable.Count() .

C'est la plupart des éléments pertinents langue aspects. Ensuite, il y a les implémentations des opérateurs de requête standard, dans les fournisseurs LINQ tels que LINQ to Objects et LINQ to SQL, etc. J'ai une présentation sur la façon dont il est raisonnablement simple d'implémenter LINQ to Objects - elle se trouve sur le site Web de la Commission européenne. "Conversations" de la page du site Web C# in Depth.

Le fonctionnement des fournisseurs tels que LINQ to SQL s'effectue généralement par le biais de la fonction Queryable classe. Au fond, ils traduisent les arbres d'expression en d'autres formats de requête, puis construisent des objets appropriés avec les résultats de l'exécution de ces requêtes hors processus.

Cela couvre-t-il tout ce qui vous intéresse ? S'il y a quelque chose en particulier que vous voulez encore savoir, il suffit de modifier votre question et je vais essayer.

0 votes

@JonSkeet J'ajouterais les génériques (et l'inférence de type et les var ) aux aspects essentiels qui rendent linq possible .

0 votes

@nawfal : J'ai eu var et, bien que les génériques soient nécessaires, ils faisaient déjà partie de C# 2 et étaient largement utilisés en dehors de LINQ. Si nous devons énumérer tout nécessaire, cela devrait inclure "l'accès aux propriétés", et "les variables", etc.

0 votes

@JonSkeet var mérite d'être mentionné en dehors des types anonymes, car il aurait été rebutant d'écrire IOrderedEnumerable<T> etc, de même que l'inférence de type. Hmmm, personnellement je pense que les génériques (même s'ils sont arrivés avant) sont peu différents de l'accès aux propriétés quand il s'agit de leur utilité en linq, ymmv.

5voto

LINQ est fondamentalement une combinaison des caractéristiques discrètes de C# 3.0 :

  • inférence du type de variable locale
  • propriétés automatiques (non implémentées dans VB 9.0)
  • méthodes d'extension
  • expressions lambda
  • initialisateurs de type anonymes
  • compréhension des requêtes

Pour plus d'informations sur le parcours pour y arriver (LINQ), voir cette vidéo d'Anders dans LANGNET 2008 :

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

2 votes

Les propriétés automatiques ne jouent pas de rôle dans LINQ et ne le sont pas dans VB9.

0 votes

Oui, vous avez raison, VB 9.0 ne l'a pas. Je vais modifier ma réponse.

1 votes

Je pense que vous avez manqué le point principal, à savoir que les propriétés automatiques n'ont rien à voir avec LINQ.

3voto

Ruslan Points 1421

En termes simples, le compilateur prend votre demande de code et la convertit en un ensemble de classes et d'appels génériques. En dessous, dans le cas de Linq2Sql, une requête SQL dynamique est construite et exécutée en utilisant DbCommand, DbDataReader, etc.

Disons que vous l'avez :

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

il est converti en code suivant :

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

Beaucoup de génériques, des frais généraux énormes.

1 votes

Des frais généraux énormes ? Que voulez-vous dire ?

0 votes

Le Select about finira par appeler la méthode execute d'un provider, qui initialise le mode, détermine la connexion, vérifie les transactions, initialise les collections de paramètres, appelle un lecteur, traduit les résultats, parse... des milliers de lignes.

3 votes

@Ruslan, presque toutes les choses que vous avez mentionnées, vous devez les faire de toute façon, donc elles ne sont pas considérées comme des frais généraux, et d'ailleurs, vérifier certaines choses comme s'il y a une transaction attachée a un coût minuscule par rapport à l'exécution de la commande sur le DB.

2voto

Hemant Points 7612

En fait, linq est un mélange de certaines facilités de langage (compilateur) et de certaines extensions de framework. Ainsi, lorsque vous écrivez des requêtes linq, elles sont exécutées en utilisant des interfaces appropriées telles que IQuerable. Notez également que le runtime n'a aucun rôle dans linq.

Mais il est difficile de rendre justice à linq dans une réponse courte. Je vous recommande de lire un livre pour vous familiariser avec lui. Je ne suis pas sûr du livre qui vous parle des aspects internes de Linq mais Linq en action donne un bon coup de main à ce sujet.

-3voto

J'ai un petit programme C# qui démontre l'implémentation de LINQ en 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;
        }
    }
}

Utilisez des points d'arrêt appropriés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X