2017-05-29 19 views
0

我正在使用表達式樹開發動態業務規則引擎。因此,我不確定編譯期間的參數數量。我必須創建動態輸入參數。使用動態輸入參數的Expression.Lambda

對於這個要求,我使用Expression.Lambda像下面,但喜歡它的投擲的錯誤:

爲拉姆達聲明提供的參數的數量不正確

我可能是錯的語法。我提到微軟網站,他們正在用單個參數創建Func,而不是參數數組。

即使有大約16點的參數,它們被單獨地分別聲明每個參數等Func< T1,T2,T3,T4,T5...T16 >https://msdn.microsoft.com/en-us/library/dd402862(v=vs.110).aspx

有任何解決方法而不是單獨聲明我們可以通過作爲數組?

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

在上述語法中,pe是具有多個參數的ParameterExpression[]數組。

在上面的語法,而不是T[]陣列,如果我使用的單個T的元素,它的工作的罰款像

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

但問題是T的數量不會在編譯時是已知的。

請糾正我如果我在這裏做錯了什麼。

+0

什麼只是Expression.Lambda(...)? –

+0

表達式。Lambda是我用來從前面的操作中形成的表達式tress創建委託或者作爲參數傳遞給其他函數的API函數,我沒有在這裏展示,我只是使用表達式樹存儲的表達式樹變量ruleExpression –

+0

我也嘗試了Plain.Lamda –

回答

1

創建具有運行時指定數量參數的委託的簡單示例。我認爲這幾乎是無用的(因爲你必須通過DynamicInvoke調用委託...你沒有任何安全性,而且你正在使用最慢的反射執行方法)。

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(); 
} 

Expression.Lambda意願真理genete一個Expression<Func<...>>(或Expression<Action<...>>),其中Func<...>是基於給出的參數計算出的,但Expression<...>LambdaExpression一個子類。如果Func<>Action<>的參數太多,則即使在運行時也會生成委託類型。

然後:

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); 

如果你想有一個Func<T[], T>它是可能的(並且可能是一個更好的主意):

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(); 
} 

您只需使用Expression.ArrayIndex()

再比如說:

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

偉大的先生Xanatos,非常感謝你解釋事物並提供代碼示例。我嘗試你的方法。 –