J'adore utiliser LINQ dans .NET, mais je veux savoir comment cela fonctionne en interne ?
@JonSkeet J'ajouterais les génériques (et l'inférence de type et les var
) aux aspects essentiels qui rendent linq possible .
J'adore utiliser LINQ dans .NET, mais je veux savoir comment cela fonctionne en interne ?
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.
@JonSkeet J'ajouterais les génériques (et l'inférence de type et les var
) aux aspects essentiels qui rendent linq possible .
@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.
@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.
LINQ est fondamentalement une combinaison des caractéristiques discrètes de C# 3.0 :
Pour plus d'informations sur le parcours pour y arriver (LINQ), voir cette vidéo d'Anders dans LANGNET 2008 :
Je pense que vous avez manqué le point principal, à savoir que les propriétés automatiques n'ont rien à voir avec LINQ.
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.
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.
@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.
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.
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 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.
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
0 votes
@BrianR.Bondy oui utile. J'ai trouvé le livre ici. livebook.manning.com/#!/livre/c-pointe-en-profondeur-troisième-edition/
0 votes
Il s'agit d'un cours sur PluralSight : Architecture LINQ . El "LINQ - Au-delà des requêtes" vous permettra d'avoir une bonne compréhension de la façon dont les méthodes de type LINQ sont conçues. app.pluralsight.com/library/courses/linq-architecture
0 votes
Ceci explique ce qui se passe en coulisses dans .NET Framework et .NET 5 : levelup.gitconnected.com/