Calling (params object[]) with Expression[]

2019-02-17 07:01发布

问题:

I'm trying to call String.Format from with in a Linq.Expression tree. Here's a quick example:

    var format = Expression.Constant("({0}) {1}");
    var company = Expression.Property(input, membernames.First());
    var project = Expression.Property(input, membernames.Last());
    var args = new Expression[] {format, company, project};
    var invoke = Expression.Call(method,args);

The issue however is that String.Format has the signature of:

String.Format(string format, params object[] args)

and I'm trying to pass in Expression[].

Now I could go through all the trouble of creating an array, populating it with the results of my expressions, but what I really want the result to be, is something like this:

String.Format("({0}) {1}", input.foo, input.bar)

How do I go about calling a params function via Linq Expressions?

回答1:

What params actually does is just to specify ParamArrayAttribute for that parameter. The C# compiler understands this, and creates the array behind the scenes.

Expressions don't understand this, so you actually have to create the array by yourself, if you want to call a method with params. This can be also seen by the fact that when you assign a lambda using params-method to an expression, the expression contains the array creation:

Expression<Func<string>> expression = () => string.Format("",1,2,3,4);
string expressionString = expression.ToString();

Here, expressionString will contain this string:

() => Format("", new [] {Convert(1), Convert(2), Convert(3), Convert(4)})

To create an expression that creates an array, use the Expression.NewArrayInit() method.

That being said, if you only want two parameters (or one or three), there is an overload of string.Format() that you can use directly from an expression.



回答2:

params is just syntactic sugar. Ultimately the parameter is just an array. Therefore, the parameter type should be object[] and an expression describing such an array is what you should pass as the second argument. In other words, you should only have two arguments, not three. And the second argument should be a two-element array containing what is currently your 2nd and 3rd arguments.