Mit einem Methodenaufruf ist es einfach, von einem Lambda zu einem Ausdruck zu wechseln ...
public void GimmeExpression(Expression<Func<T>> expression)
{
((MemberExpression)expression.Body).Member.Name; // "DoStuff"
}
public void SomewhereElse()
{
GimmeExpression(() => thing.DoStuff());
}
Aber ich möchte den Func nur in seltenen Fällen in einen Ausdruck verwandeln ...
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());
}
Die Zeile, die nicht funktioniert, gibt mir den Fehler beim Kompilieren Cannot implicitly convert type 'System.Func<T>' to 'System.Linq.Expressions.Expression<System.Func<T>>'
. Eine explizite Besetzung löst die Situation nicht. Gibt es eine Möglichkeit, dies zu tun, die ich übersehen habe?
at lambda_method(Closure )
für den Aufruf des kompilierten Delegaten anzeigt.Antworten:
Oh, es ist überhaupt nicht einfach.
Func<T>
repräsentiert einen generischendelegate
und keinen Ausdruck. Wenn Sie dies auf irgendeine Weise tun können (aufgrund von Optimierungen und anderen vom Compiler vorgenommenen Vorgängen werden möglicherweise einige Daten weggeworfen, sodass der ursprüngliche Ausdruck möglicherweise nicht wiederhergestellt werden kann), wird die IL im laufenden Betrieb zerlegt und auf den Ausdruck schließen (was keineswegs einfach ist). Das Behandeln von Lambda-Ausdrücken als data (Expression<Func<T>>
) ist eine Magie des Compilers (im Grunde erstellt der Compiler einen Ausdrucksbaum im Code, anstatt ihn in IL zu kompilieren).Verwandte Tatsache
Aus diesem Grund sind Sprachen, die Lambdas auf die Spitze treiben (wie Lisp), als Dolmetscher oft einfacher zu implementieren . In diesen Sprachen sind Code und Daten im Wesentlichen dasselbe (auch zur Laufzeit ), aber unser Chip kann diese Form von Code nicht verstehen. Daher müssen wir eine solche Maschine emulieren, indem wir darauf einen Interpreter aufbauen, der sie versteht (the Auswahl von Lisp wie Sprachen) oder Einbußen bei der Leistung (Code entspricht nicht mehr genau den Daten) bis zu einem gewissen Grad (Auswahl von C #). In C # gibt der Compiler die Illusion, Code als Daten zu behandeln, indem Lambdas zur Kompilierungszeit als Code (
Func<T>
) und Daten (Expression<Func<T>>
) interpretiert werden können .quelle
eval
müssten Sie den Compiler starten, aber ansonsten gibt es überhaupt kein Problem damit.Expression
zu Ihrer Wrapper-Aktion erstellen , aber keine Informationen zum Ausdrucksbaum über die Interna desdangerousCall
Delegaten enthalten.quelle
Func
werden in einem neuen Ausdruck ausgeblendet. Dies fügt einfach eine Datenschicht über Code hinzu. Sie können eine Ebene durchlaufen, um Ihren Parameterf
ohne weitere Details zu finden, sodass Sie genau dort sind, wo Sie begonnen haben.Was Sie wahrscheinlich tun sollten, ist die Methode umzudrehen. Nehmen Sie einen Ausdruck> auf und kompilieren Sie ihn und führen Sie ihn aus. Wenn dies fehlschlägt, müssen Sie bereits den Ausdruck untersuchen.
Natürlich müssen Sie die Auswirkungen auf die Leistung berücksichtigen und feststellen, ob Sie dies wirklich tun müssen.
quelle
Sie können jedoch auch über die .Compile () -Methode in die andere Richtung gehen - nicht sicher, ob dies für Sie nützlich ist:
quelle
Wenn Sie manchmal einen Ausdruck und manchmal einen Delegaten benötigen, haben Sie zwei Möglichkeiten:
Expression<...>
Version und nur.Compile().Invoke(...)
dann, wenn Sie einen Delegaten möchten. Offensichtlich hat dies Kosten verursacht.quelle
NJection.LambdaConverter ist eine Bibliothek, die Delegaten in Ausdruck konvertiert
quelle
quelle
call.Target
Teil, der mich umbrachte. Es funktionierte jahrelang und hörte dann plötzlich auf zu arbeiten und begann sich über ein statisches / nicht statisches bla bla zu beschweren. Trotzdem danke!JB Evain vom Cecil Mono-Team macht einige Fortschritte, um dies zu ermöglichen
http://evain.net/blog/articles/2009/04/22/converting-delegates-to-expression-trees
quelle
Veränderung
Zu
quelle