在没有实例的实例方法上创建表达式

时间:2011-06-09 19:59:44

标签: .net reflection c#-4.0 lambda

我有一个泛型类,它有一个方法'Call',它带有泛型返回类型和lambda表达式作为参数。这必须使用反射生成,并且由于类型未知,我需要创建lambda表达式。我有一个下面列出的工作解决方案,但我不喜欢必须从泛型类中获取实例,因为它是私有的并且在检索上做了一些逻辑。

班级:

public class Proxy<T>
{
    public TR Call<TR>(Func<T, TR> serviceInvoke)
    private T Instance
}

反思用法:

var serviceInstance = proxy.GetType().GetProperty("Instance", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(proxy, null);
var serviceMethod = type.GetMethod(rule.ServiceMethodName);
var parameters = serviceMethod.GetParameters().Select(parameterInfo => PropertyChainNavigator.GetValueForPropertyChain(((string)rule.Parameters[parameterInfo.Name]).Split(new[] { '.' }), context)).ToArray();
var thisParam = Expression.Constant(serviceInstance);
var valueParams = parameters.Select(Expression.Constant).ToList();
var call = Expression.Call(thisParam, serviceMethod, valueParams);
var func = Expression.Lambda(call, Expression.Parameter(type)).Compile();
var callMethod = proxy.GetType().GetMethods().Where(x => x.Name == "Call" && x.ReturnType != typeof(void)).First().MakeGenericMethod(serviceMethod.ReturnType);
result = callMethod.Invoke(proxy, new[] { func });

正常用法:

var proxy = new Proxy<ITestClass>();
proxy.Call(x => x.Method);

我试图将Expression.Call更改为不接受实例,但这仅适用于静态方法。有没有人知道我创建调用的方法,将其转换为lambda并使其编译而不会出错

2 个答案:

答案 0 :(得分:3)

如果您使用lambda而不是表达式,那么您当前的代码将如下所示:

var serviceInstance = …; // retrieve using reflection
proxy.Call(i => serviceInstance.CallMethod(parameters));

请注意,lambda采用参数i,但不使用它。我假设您想直接在i上调用该方法,例如:

proxy.Call(i => i.CallMethod(parameters));

为此,请将Expression.Parameter()的值用作thisParam

var thisParam = Expression.Parameter(type, "i"); // the name is optional
var call = Expression.Call(thisParam, serviceMethod, valueParams);
var func = Expression.Lambda(call, thisParam).Compile();

答案 1 :(得分:0)

public class Proxy<T>
{
    public TR Call<TR>(Func<T, TR> serviceInvoke)
    {
        return serviceInvoke(Instance);
    }

    private T Instance;
}

这不是你需要的全部吗?为什么需要使用反射来获取T实例?