我希望仅通过Type.GetMethod()检索的methodinfo对象创建一个可缓存的lambda表达式,而无需对该函数的类型转换进行编码。
除了从编译表达式转换为类型化的可调用函数之外,我已经开始工作了。
var parameters = Array.ConvertAll(method.GetParameters(), input => Expression.Parameter(input.ParameterType));
var instanceExp = Expression.Constant(_implementation);
var call = Expression.Call(instanceExp, method, parameters);
var exp = Expression.Lambda(call, parameters).Compile();
缺少的是:
Func<T1,T2,T3> castExp = (Func<T1,T2,T3>)exp;
我想要做的是转换为具有特定数量参数的函数,而不指定特定类型:
Func<object,object,object> castExp = (Func<object,object,object>)exp;
这样我就可以调用exp(o1,o2,o3)而无需编写o1等类型。 但是存在运行时错误,将Func类型的函数强制转换为Func。
如何将函数转换为某种形式的函数&lt; ,,&gt;允许传递未指定类型的参数?
(顺便说一下:不能更改要调用的方法的签名。)
答案 0 :(得分:1)
-1我已经部分解决了我的问题。
如果方法不使用in / out / ref参数,我能够为未知签名的方法创建表达式。在那种情况下,我不得不回到MethodInfo.Invoke调用。
private object CallMethod(MethodInfo method, object obj, object[] parameters) {
// Methods with void as return must be cast to Action instead of Function
var voidMethod = voidMethod = method.ReturnType == typeof(void);
// Methods with ref parameters can be called but the parameters won't work.
var refMethod = Array.FindAll(method.GetParameters(), info => info.ParameterType.IsByRef;
var paramExprs = getParamExpr(method);
var paramTypes = getParamTypes(method, paramExprs);
var instanceExp = Expression.Convert(paramExprs[0], method.DeclaringType);
Expression call = null;
if (voidMethod) {
call = Expression.Call(instanceExp, method, paramTypes);
} else {
call = Expression.Convert(Expression.Call(instanceExp, method, paramTypes), typeof(object));
}
exp = Expression.Lambda(call, paramExprs).Compile();
if (voidMethod) {
switch (method.GetParameters().Length) {
case 0:
((Action<object>)exp)(_obj);
break;
case 1:
((Action<object, object>)exp)(_obj, parameters[0]);
break;
// Continue here with more case statements.
}
} else {
switch (method.GetParameters().Length) {
case 0:
result = ((Func<object, object>)exp)(_obj);
break;
case 1:
result = ((Func<object, object, object>)exp)(_obj, parameters[0]);
break;
// Continue here with more case statements
}
}
// Error handling omited
return result;
}
private List<ParameterExpression> getParamExpr(MethodInfo method) {
var list = new List<ParameterExpression>();
list.Add(Expression.Parameter(typeof(object), "obj"));
list.AddRange(Array.ConvertAll(method.GetParameters(), input => Expression.Parameter(typeof(object))));
return list;
}
private List<Expression> getParamTypes(MethodInfo method, List<ParameterExpression> inList) {
var list = new List<Expression>();
var methParams = method.GetParameters();
list.AddRange(
// Skip the first item as this is the object on which the method is called.
inList.Skip(1).Select(
input => Expression.Convert(
input,
Type.GetType(
methParams[inList.IndexOf(input)-1].ParameterType.FullName.Replace("&", string.Empty)))));
return list;
}
我希望它完整,因为我遗漏了大量的错误处理样板。
表达式对象可以被缓存,但每次要调用它们时都必须经过转换。
答案 1 :(得分:0)
我不是100%确定你想做什么,但你可以创建一个能够返回你改变的功能的函数:
Func<T1, T2, T3> GetAlteredFunction<T1, T2, T3>(Func<T1, T2, T3> func)
{
//execute your logic and return the result
}
所以你可以打电话给
Func<object,object,object> castExp = GetAlteredFunction(exp);