Je me demande quelle est exactement la différence entre envelopper un délégué dans Expression<>
et pas ?
Je regarde Expression<Foo>
étant beaucoup utilisé avec LinQ, mais jusqu'à présent, je n'ai trouvé aucun article expliquant la différence entre cela et l'utilisation d'un délégué.
Par exemple.
Func<int, bool> Is42 = (value) => value == 42;
vs.
Expression<Func<int, bool>> Is42 = (value) => value == 42;
En stockant un lambda en tant que délégué, vous stockez une instance spécifique d'un délégué qui effectue une action. Il ne peut pas être modifié, appelez-le simplement. Une fois que vous avez votre délégué, vous avez des options limitées pour inspecter ce qu'il fait et ainsi de suite.
En stockant un lambda en tant qu'expression, vous stockez une arborescence d'expression qui représente le délégué. Il peut être manipulé pour faire d'autres choses comme changer ses paramètres, changer le corps et lui faire faire quelque chose de radicalement différent. Il pourrait même être recompilé à un délégué afin que vous puissiez l'appeler si vous le souhaitez. Vous pouvez facilement inspecter l'expression pour voir quels sont ses paramètres, ce qu'elle fait et comment elle le fait. C'est quelque chose qu'un fournisseur de requêtes peut utiliser pour comprendre et traduire une expression dans un autre langage (comme écrire une requête SQL pour une arborescence d'expressions correspondante).
Il est également beaucoup plus facile de créer un délégué dynamiquement à l'aide d'expressions que d'émettre le code. Vous pouvez considérer votre code à un niveau supérieur comme des expressions très similaires à la façon dont un compilateur voit le code au lieu d'aller de bas niveau et d'afficher votre code sous forme d'instructions IL.
Ainsi, avec une expression, vous êtes capable de faire bien plus qu'un simple délégué anonyme. Bien que ce ne soit pas vraiment gratuit, les performances seront prises si vous exécutez des expressions compilées par rapport à une méthode régulière ou à un délégué anonyme. Mais cela ne pose peut-être pas de problème car les autres avantages de l'utilisation d'expressions peuvent être importants pour vous.
Func<>
est juste un type de délégué. Une expression est une représentation à l'exécution de l'arborescence complète de opérations qui, facultativement, peut être compilée au moment de l'exécution dans un délégué. C'est cet arbre qui est analysé par des analyseurs d'expressions comme Linq-to-SQL pour générer des instructions SQL ou faire d'autres choses intelligentes. Lorsque vous affectez un lambda à un type d'expression, le compilateur génère cette arborescence d'expression ainsi que le code IL habituel. Plus d'informations sur les arbres d'expression .
Pour illustrer d'autres réponses, si vous compilez ces 2 expressions et regardez le code généré par le compilateur, voici ce que vous verrez:
Func<int, bool> Is42 = (value) => value == 42;
Func<int, bool> Is42 = new Func<int, bool>((@value) => value == 42);
Expression<Func<int, bool>> Is42 = (value) => value == 42;
ParameterExpression[] parameterExpressionArray;
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "value");
Expression<Func<int, bool>> Is42 = Expression.Lambda<Func<int, bool>>(Expression.Equal(parameterExpression, Expression.Constant(42, typeof(int))), new ParameterExpression[] { parameterExpression });
Arbres d'expressions vous permettent d'inspecter le code à l'intérieur de l'expression, dans votre code.
Par exemple, si vous avez transmis cette expression: o => o.Name
, votre code pourrait découvrir que la propriété Name
était en cours d'accès à l'intérieur de l'expression.
Fournit la classe de base à partir de laquelle les classes qui représentent les nœuds d'arborescence d'expression sont dérivées.
System.Linq.Expressions.BinaryExpression
System.Linq.Expressions.BlockExpression
System.Linq.Expressions.ConditionalExpression
System.Linq.Expressions.ConstantExpression
System.Linq.Expressions.DebugInfoExpression
System.Linq.Expressions.DefaultExpression
System.Linq.Expressions.DynamicExpression
System.Linq.Expressions.GotoExpression
System.Linq.Expressions.IndexExpression
System.Linq.Expressions.InvocationExpression
System.Linq.Expressions.LabelExpression
System.Linq.Expressions.LambdaExpression
System.Linq.Expressions.ListInitExpression
System.Linq.Expressions.LoopExpression
System.Linq.Expressions.MemberExpression
System.Linq.Expressions.MemberInitExpression
System.Linq.Expressions.MethodCallExpression
System.Linq.Expressions.NewArrayExpression
System.Linq.Expressions.NewExpression
System.Linq.Expressions.ParameterExpression
System.Linq.Expressions.RuntimeVariablesExpression
System.Linq.Expressions.SwitchExpression
System.Linq.Expressions.TryExpression
System.Linq.Expressions.TypeBinaryExpression
System.Linq.Expressions.UnaryExpression
http://msdn.Microsoft.com/en-us/library/system.linq.expressions.expression.aspx
L'arbre d'expression représente l'expression linq qui peut être analysée et par exemple transformée en requête SQL.
À tout ce que l'autre a écrit (c'est tout à fait correct), j'ajouterai que grâce à la classe Expression
, vous pouvez créer de nouvelles méthodes au moment de l'exécution. Il y a des limites. Tout ce que vous pouvez faire en C # ne peut pas être fait dans une arborescence Expression
(au moins dans .NET 3.5. Avec .NET 4.0, ils ont ajouté un grand nombre de Expression
"types" possibles ). L'utilisation de ceci pourrait être (par exemple) de créer une requête dynamique et de la transmettre à LINQ-to-SQL ou de faire un filtrage basé sur l'entrée de l'utilisateur ... (vous pouvez toujours le faire avec CodeDom si tout ce que vous voulez était une méthode dynamique incompatible avec LINQ-to-SQL, mais émettre directement du code IL est assez difficile :-))