2017-05-29 4 views
0

Ich entwickle dynamische Business Rule-Engine mit Expression Tree. Daher bin ich nicht sicher über die Anzahl der Parameter während der Kompilierzeit. Ich muss dynamische Eingabeparameter erstellen.Expression.Lambda mit dynamischen Eingabeparametern

Für diese Anforderung verwende ich die Expression.Lambda wie unten, aber seinen Wurf Fehler wie:

Falsche Anzahl von Parametern für die Lambda-Erklärung geliefert

ich falsch sein kann, in die Syntax. Ich habe auf Microsoft-Website verwiesen, sie erstellen Func mit einzelnen Parametern, nicht Array von Parametern.

Auch wenn es rund 16 Parameter, sie sind einzeln jeden Parameter separat wie Func< T1,T2,T3,T4,T5...T16 >https://msdn.microsoft.com/en-us/library/dd402862(v=vs.110).aspx

erklärt Gibt es eine Abhilfe statt einzeln deklarieren können wir als Array übergeben?

var lambdaExpression = Expression.Lambda< Func< T[], bool>>(ruleExpression, pe).Compile(); 

In der obigen Syntax PE sind die ParameterExpression[] Array mehr Parameter aufweisen.

In der obigen Syntax anstelle von T[] Array, wenn ich einzelne T-Elemente verwenden, seine adaequat wie

var lambdaExpression = Expression.Lambda< Func< T,T, bool>>(ruleExpression, pe).Compile(); 

aber das Problem ist die Anzahl der T wird nicht während der Kompilierung bekannt sein.

Bitte korrigieren Sie mich Wenn ich hier etwas falsch mache.

+0

Was ist nur Expression.Lambda (...)? –

+0

Ausdruck.Lambda ist die API-Funktion, die ich benutze, um Delegat aus Ausdruckstress zu erzeugen, das in vorherigen Operationen gebildet wurde oder als Parameter an andere Funktionen übergeben wurde, die ich hier nicht zeige. Ich habe nur die Ausdrucksbaumvariable ruleExpression verwendet, wo der Ausdrucksbaum gespeichert ist –

+0

Ich versuchte einfachen Expression.Lamda sowie –

Antwort

1

Einfaches Beispiel für die Erstellung eines Delegaten mit einer Laufzeit zugeordneten Anzahl von Parametern. Ich halte dies für nahezu nutzlos (weil Sie den Delegierten über DynamicInvoke anrufen müssen ... Sie haben keine Sicherheit und Sie verwenden die langsamste Reflexionsausführungsmethode).

public static Delegate CreateLambda(int num) 
{ 
    var parameters = new ParameterExpression[num]; 

    for (int i = 0; i < num; i++) 
    { 
     parameters[i] = Expression.Parameter(typeof(int), "p" + i); 
    } 

    // We sum all the parameters together 
    Expression sum = parameters[0]; 

    for (int i = 1; i < num; i++) 
    { 
     sum = Expression.Add(sum, parameters[i]); 
    } 

    Expression body = sum; 

    LambdaExpression exp = Expression.Lambda(body, parameters); 
    return exp.Compile(); 
} 

Der Expression.Lambda Willen in Wahrheit Genete ein Expression<Func<...>> (oder Expression<Action<...>>), wo die Func<...> berechnet auf der Basis der Parameter gegeben, aber Expression<...> eine Unterklasse von LambdaExpression ist. Wenn zu viele Parameter für Func<> oder Action<> vorhanden sind, wird zur Laufzeit sogar der Delegattyp generiert.

und dann:

int num = 5; 
Delegate del = CreateLambda<double>(num); 

// Note that we have to convert to object the various parameters, 
// because DynamicInvoke uses a object[] 
object[] values = Enumerable.Range(1, num).Select(x => (object)(double)x).ToArray(); 
double result = (double)del.DynamicInvoke(values); 

Console.WriteLine("{0}={1}", string.Join("+", values), result); 

Wenn Sie eine Func<T[], T> es möglich haben wollen, ist (und ist wahrscheinlich eine viel bessere Idee):

public static Func<T[], T> CreateLambda<T>(int num) 
{ 
    var parameter = Expression.Parameter(typeof(T[]), "p"); 

    // We sum all the parameters together 
    Expression sum = Expression.ArrayIndex(parameter, Expression.Constant(0)); 

    for (int i = 1; i < num; i++) 
    { 
     sum = Expression.Add(sum, Expression.ArrayIndex(parameter, Expression.Constant(i))); 
    } 

    Expression body = sum; 

    var exp = Expression.Lambda<Func<T[], T>>(body, parameter); 
    return exp.Compile(); 
} 

Sie einfach Expression.ArrayIndex() verwenden.

Dann zum Beispiel:

int num = 5; 
Func<double[], double> del = CreateLambda<double>(num); 

double[] values = Enumerable.Range(1, num).Select(x => (double)x).ToArray(); 
double result = del(values); 

Console.WriteLine("{0}={1}", string.Join("+", values), result); 
+0

Großer Herr Xanatos, Vielen Dank für die Erklärung der Dinge und die Bereitstellung von Codebeispiel. Ich versuche deinen Ansatz. –

Verwandte Themen