Wie kann ich einen Ausdruck Baum in eine aufrufbare Methode, C # kompilieren?
-
19-08-2019 - |
Frage
Ich habe einen Ausdruck Baum, den ich durch Parsen einer XML-unter Verwendung des Ausdrucks Klasse in C # erstellt haben. Sehen Sie diese Frage .
ich nur haben zu Addieren, Subtrahieren, Dividieren, Multiplizieren, Parameter und und Oder in meinem Ausdruck Baum. Gibt es eine Möglichkeit, diese ExpressionTree in eine aufrufbare Methode zu konvertieren? ... oder muss ich manuell die IL emittieren?
Mit freundlichen Grüßen
Lösung
Hier ist ein Beispiel der beiden Ansätze. Wenn ich etwas verpasst haben, oder Sie weitere Informationen wünschen, lassen Sie es mich wissen.
static void Main()
{
// try to do "x + (3 * x)"
var single = BuildSingle<decimal>();
var composite = BuildComposite<decimal>();
Console.WriteLine("{0} vs {1}", single(13.2M), composite(13.2M));
}
// utility method to get the 3 as the correct type, since there is not always a "int x T"
static Expression ConvertConstant<TSource, TDestination>(TSource value)
{
return Expression.Convert(Expression.Constant(value, typeof(TSource)), typeof(TDestination));
}
// option 1: a single expression tree; this is the most efficient
static Func<T,T> BuildSingle<T>()
{
var param = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Add(param, Expression.Multiply(
ConvertConstant<int, T>(3), param));
var lambda = Expression.Lambda<Func<T, T>>(body, param);
return lambda.Compile();
}
// option 2: nested expression trees:
static Func<T, T> BuildComposite<T>()
{
// step 1: do the multiply:
var paramInner = Expression.Parameter(typeof(T), "inner");
Expression bodyInner = Expression.Multiply(
ConvertConstant<int, T>(3), paramInner);
var lambdaInner = Expression.Lambda(bodyInner, paramInner);
// step 2: do the add, invoking the existing tree
var paramOuter = Expression.Parameter(typeof(T), "outer");
Expression bodyOuter = Expression.Add(paramOuter, Expression.Invoke(lambdaInner, paramOuter));
var lambdaOuter = Expression.Lambda<Func<T, T>>(bodyOuter, paramOuter);
return lambdaOuter.Compile();
}
Ich persönlich würde auf dem ersten Verfahren zielt darauf ab; es sich einfacher und effizienter zu gestalten. Dies kann die ursprünglichen Parameter über einen Stapel von verschachteltem Code beinhaltet vorbei, aber es so sein. Ich habe einige Code irgendwo bekam, dass die „Invoke“ -Ansatz (Composite) nimmt und wieder schreibt den Baum als der erste Ansatz (single) - aber es ist recht komplex und lang. Aber sehr nützlich für die Framework-Entity (die Expression.Invoke nicht unterstützt).
Andere Tipps
Sie benötigen ein Lambda erstellen - d. H
var lambda = Expression.Lambda<Func<float,int>>(body, param);
Func<float,int> method = lambda.Compile();
int v = method(1.0); // test
Dabei steht "Körper" ist Ihr Ausdrucksbaum (unter einem Schwimmer, die Rückkehr einen int) Beteiligung des ParameterExpression
param.