Ich bin Ausdrucksbaum erstellen und es gibt eine Situation, wo ich ein Lambda in einem anderen Lambda erstellen und innere in einer Klasse speichern und diese Klasse in Ausdrucksbaum hinzufügen müssen. Dies ist einfaches Beispiel, was ich versuche zu tun (dieser Code nicht kompiliert):Ausdruck Baum - kompilieren inneren Lambda in äußeren Lambda - Scoping Auflösung
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace SimpleTest {
public class LambdaWrapper {
private Delegate compiledLambda;
public LambdaWrapper(Delegate compiledLambda) {
this.compiledLambda = compiledLambda;
}
public dynamic Execute() {
return compiledLambda.DynamicInvoke();
}
}
public class ForSO {
public ParameterExpression Param;
public LambdaExpression GetOuterLambda() {
IList<Expression> lambdaBody = new List<Expression>();
Param = Expression.Parameter(typeof(object), "Param");
lambdaBody.Add(Expression.Assign(
Param,
Expression.Constant("Value of 'param' valiable"))
);
lambdaBody.Add(Expression.Call(
null,
typeof(ForSO).GetMethod("Write"),
Param)
);
Delegate compiledInnerLambda = GetInnerLambda().Compile();
LambdaWrapper wrapper = new LambdaWrapper(compiledInnerLambda);
lambdaBody.Add(Expression.Constant(wrapper));
//lambdaBody.Add(GetInnerLambda());
return Expression.Lambda(
Expression.Block(
new ParameterExpression[] { Param },
lambdaBody));
}
public LambdaExpression GetInnerLambda() {
return Expression.Lambda(
Expression.Block(
Expression.Call(null,
typeof(ForSO).GetMethod("Write"),
Expression.Constant("Inner lambda start")),
Expression.Call(null,
typeof(ForSO).GetMethod("Write"),
Param),
Expression.Call(null,
typeof(ForSO).GetMethod("Write"),
Expression.Constant("Inner lambda end"))
)
);
}
public static void Write(object toWrite) {
Console.WriteLine(toWrite);
}
public static void Main(string[] args) {
ForSO so = new ForSO();
LambdaWrapper wrapper = so.GetOuterLambda().Compile()
.DynamicInvoke() as LambdaWrapper;
wrapper.Execute();
//(so.GetOuterLambda().Compile().DynamicInvoke() as Delegate).DynamicInvoke();
}
}
}
Problem in GetInnerLambda().Compile()
Linie in GetOuterLambda
Methode. Ich bin mir einer Lösung bewusst - sie ist im kommentierten Teil des Codes. Damit funktioniert alles gut, aber ich brauche einen Wrapper als Rückgabewert, nicht Ausdruck Teilbaum (es könnte ok sein, den inneren Lambda-Teilbaum in LambdaWrapper zu speichern und später zu kompilieren, aber das gleiche Problem tritt auf).
Fehler Ich bekomme ist Unhandled Exception: System.InvalidOperationException: variable 'Param' of type 'System.Object' referenced from scope '', but it is not defined
.
Wenn ich Param
hinzufügen, um Variablen in innerem Lambda zu blockieren, kompiliert Code kompiliert, aber Param hat Wert in äußerem Lambda nicht zugewiesen (und das macht Sinn).
Wie kann das gelöst werden?
Danke für die Antwort.Was ich an diesem Ansatz nicht mag, ist, dass diese Lambdas tatsächliche Funktionen sind, und sie können ihre Parameter haben (ich habe diesen Teil nicht in Frage gestellt, weil ich damit kein Problem habe), und Param ist nicht nur Variable muss ich zugreifen (es kann eine Menge von ihnen sein), so denke ich nicht, dass addig künstliche Parameter zur Auflösung von Scoping ist sehr elegante Lösung. –
Aktualisierte Antwort könnte nur für mich arbeiten, aber ich muss überprüfen, wenn ich zurück zu meinem Arbeitscomputer komme. Danke ... –
Ich habe überprüft, ob das für mich funktioniert. Fast :). Ich ging noch einen Schritt weiter und erstellte DynamicExpression zum Erstellen einer Instanz von LambdaWrapper. Ich musste Binder erstellen, also benötigt diese Soulution mehr Arbeit, aber ich hatte sie sowieso schon in meinem Hauptprojekt. Vielen Dank für Ihr Interesse an der Lösung dieses Problems :) –