说我有一些像这样的功能
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'
。
答案 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..."
}
}