使用命名参数常量调用MethodCallExpression

时间:2017-07-09 20:52:51

标签: c# dynamic reflection lambda expression

说我有一些像这样的功能

public string TestValue(string hello, Guid world)
{
    return hello + world;
}

假设objectParams是对象Dictionary<string, object>的字典,它将参数名称映射到值,我当前正在将参数值与方法名称匹配,如下所示:

var method = this.GetType().GetMethod("TestValue");
var methodParameters = method.GetParameters();
var paramMatcher = (from paramValue in objectParams
                    from methodParam in methodParameters
                    where param.Key == clrParam.Name
                    select (name: clrParam.Name,
                            type: clrParam.ParameterType,
                            value: paramValue.Value));

然后我构建表达式来调用方法TestValue,但这是我遇到麻烦的部分。

var paramExpress = (from param in paramMatcher
                    select Expression.Assign(Expression.Parameter(param.type, param.name), Expression.Constant(param.value)));

Func<object> result = Expression.Lambda<Func<object>(Expression.Call(Expression.Constant(this),
    method, paramExpress)).Compile();
var res = result.Invoke(); //should return 'somestringxxxxxxx-xxxx...etc'

问题是我不能保证参数值是在调用顺序中所以我想依赖于要调用的参数的名称。我不确定如何正确地将常量值分配给它们的参数表达式。在编译lambda时运行此代码会导致异常System.InvalidOperationException: 'variable 'hello' of type 'System.String' referenced from scope '', but it is not defined'

1 个答案:

答案 0 :(得分:1)

Expression.Assign二进制操作,因此左侧部分中的变量采用在表达式右侧部分计算的新值。

在这些方面:

var paramExpress = (from param in paramMatcher
     select Expression.Assign(Expression.Parameter(param.type, param.name),
                Expression.Constant(param.value, param.type)));

Func<object> result = Expression.Lambda<Func<object>(Expression.Call(Expression.Constant(this),
    method, paramExpress)).Compile();

您已收到并且未使用实际参数值,这些参数值显示在二进制表达式的右侧部分中。

解决方案:

public class C
{
    public string TestValue(string hello, Guid world)
    {
        return hello + world;
    }

    public string Execute()
    {
        var objectParams = new Dictionary<string, object>()
        {
            {"hello", "somestring"},
            {"world", Guid.NewGuid()}
        };
        var method = this.GetType().GetMethod("TestValue");
        var methodParameters = method.GetParameters();
        var paramMatcher = (from paramValue in objectParams
            from methodParam in methodParameters
            where paramValue.Key == methodParam.Name
            orderby methodParam.Position  // <-- preserves original order
            select (name: methodParam.Name,
            type: methodParam.ParameterType,
            value: paramValue.Value));

        var paramExpress = (from param in paramMatcher
             select Expression.Assign(Expression.Parameter(param.type, param.name),
                    Expression.Constant(param.value, param.type)));

        var values = paramExpress.Select(v => v.Right); // !!!

        Func<string> result = Expression.Lambda<Func<string>>(Expression.Call(Expression.Constant(this),
            method, values)).Compile();
        return result.Invoke(); // returns "somestringxxxxxxx-xxxx..."
    }
}
相关问题