la conversion d'un .net Func<T> pour un .net de l'Expression<Func<T>>
À partir d'un lambda à une Expression est facile à l'aide d'un appel de méthode...
public void GimmeExpression(Expression<Func<T>> expression)
{
((MemberExpression)expression.Body).Member.Name; //"DoStuff"
}
public void SomewhereElse()
{
GimmeExpression(() => thing.DoStuff());
}
Mais je voudrais tourner la touche Func dans une expression, dans de rares cas seulement...
public void ContainTheDanger(Func<T> dangerousCall)
{
try
{
dangerousCall();
}
catch (Exception e)
{
//This next line does not work...
Expression<Func<T>> DangerousExpression = dangerousCall;
var nameOfDanger =
((MemberExpression)dangerousCall.Body).Member.Name;
throw new DangerContainer(
"Danger manifested while " + nameOfDanger, e);
}
}
public void SomewhereElse()
{
ContainTheDanger(() => thing.CrossTheStreams());
}
La ligne qui n'a pas de travail me donne l'erreur de compilation Cannot implicitly convert type 'System.Func<T>' to 'System.Linq.Expressions.Expression<System.Func<T>>'
. Un cast explicite ne permet pas de résoudre la situation. Est-il de la facilité à faire ce que je suis dominant?
- Je ne vois vraiment pas beaucoup utiliser pour le "cas rare" de l'exemple. L'appelant est en passant la touche Func<T>. Il n'est pas nécessaire de répéter à l'appelant de ce que Func<T> a (via l'exception).
- L'exception n'est pas gérée en l'appelant. Et, parce qu'il y a de multiples sites d'appel en passant dans les différents Func<T>s, la capture de l'exception en l'appelant crée la duplication.
- La trace de pile d'exception est conçu pour montrer cette information. Si l'exception est levée dans l'invocation de la touche Func<T>, cela montrera dans la trace de la pile. D'ailleurs, si vous choisissez d'aller dans l'autre sens, c'est à dire accepter une expression et le compiler pour l'invocation, vous perdez ce depuis la trace de pile serait montrer quelque chose comme
at lambda_method(Closure )
pour l'invocation de l'compilé délégué. - Je suppose que vous devriez regarder la réponse dans ce [lien][1] [1]: stackoverflow.com/questions/9377635/create-expression-from-func/...
Vous devez vous connecter pour publier un commentaire.
Ooh, c'est pas du tout facile.
Func<T>
représente un génériquedelegate
et non pas une expression. Si il n'y a aucune façon vous pouvez le faire (en raison d'optimisations et d'autres choses faites par le compilateur, certaines données peuvent être jetés, de sorte qu'il peut être impossible d'obtenir l'expression d'origine à l'arrière), ce serait de démonter le IL à la volée et en déduire l'expression (ce qui n'est pas facile). Le traitement des expressions lambda comme données (Expression<Func<T>>
) est une magie faite par le compilateur (en gros, le compilateur crée une arborescence d'expression dans le code au lieu de le compiler à l'IL).Liées fait
C'est pourquoi les langues qui poussent les lambdas à l'extrême (comme Lisp) sont souvent plus faciles à mettre en œuvre que interprètes. Dans ces langues, le code et les données sont essentiellement la même chose (même à moment de l'exécution), mais notre puce ne peut pas comprendre que la forme de code, nous avons donc pour émuler une machine de ce type par la construction d'un interprète sur le dessus de ce qui la comprend (le choix fait par Lisp comme langues) ou sacrifier la puissance (le code ne sera plus exactement égale à données) dans une certaine mesure (le choix fait par C#). En C#, le compilateur donne l'illusion de traitement de code de données en permettant lambdas être interprété comme code (
Func<T>
) et données (Expression<Func<T>>
) à moment de la compilation.eval
vous auriez besoin pour démarrer le compilateur, mais autre que cela, il n'y a aucun problème à le faire.Expression
sur votre enveloppe de l'action, mais il n'aurait pas d'expression de l'arbre d'infos sur internals dedangerousCall
délégué.Func
seront cachés dans une nouvelle Expression. Ceci ajoute simplement une couche de données sur le code; vous pourriez traverser une couche juste pour trouver votre paramètref
sans plus de détails, vous êtes là où vous avez commencé.Ce que vous devriez faire, c'est de transformer la méthode de autour de. Prendre dans une Expression>, et de les compiler et de l'exécuter. Si elle échoue, vous avez déjà l'Expression de regarder dans.
Évidemment, vous devez tenir compte de l'incidence sur les performances de ce, et de déterminer si elle est quelque chose que vous avez vraiment besoin de le faire.
Vous pouvez aller dans l'autre sens par la .Compiler() la méthode cependant que pas sûr si cela est utile pour vous:
call.Target
partie qui a été de me tuer. Il a travaillé pendant des années, et puis tout à coup cessé de fonctionner et a commencé à se plaindre d'une statique/non-statique bla bla. De toute façon, merci!NJection.LambdaConverter est une bibliothèque qui convertit les délégués à l'expression
Si vous avez parfois besoin d'une expression et a parfois besoin d'un délégué, vous avez 2 options:
Expression<...>
version, et juste.Compile().Invoke(...)
si vous souhaitez déléguer. Évidemment, cela a coûté.JB Evain de Cecil Mono l'équipe est en train de faire quelques progrès pour activer cette
http://evain.net/blog/articles/2009/04/22/converting-delegates-to-expression-trees
Changement
À