Expression creation on instance method without instance
I have a generic class that has a method 'Call' on it with a generic return type and a lambda expression as a parameter. This has to be generated with reflection, and since the types are unknown, I need to create the lambda expression the long way. I have a working solution listed below, but I do not like having to get the instance out of the generic class since it is private and does some logic on a retrieve.
Class:
public class Proxy<T>
{
public TR Call<TR>(Func<T, TR> serviceInvoke)
private T Instance
}
Reflection Usage:
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 });
Normal Usage:
var proxy = new Proxy<ITestClass>();
proxy.Call(x => x.Method);
I have tried to change the Expression.Call to not take an instance, but that only works on static methods. Does anyone kn开发者_StackOverflow社区ow of a way for me to create the call, turn it into an lambda and have it compile without erroring
If you used lambda instead of expressions, your current code would look like this:
var serviceInstance = …; // retrieve using reflection
proxy.Call(i => serviceInstance.CallMethod(parameters));
Note that the lambda takes the parameter i
, but doesn't use it. I assume you want to call the method directly on i
, i.e. something like this:
proxy.Call(i => i.CallMethod(parameters));
To do that, use the value of Expression.Parameter()
as 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();
public class Proxy<T>
{
public TR Call<TR>(Func<T, TR> serviceInvoke)
{
return serviceInvoke(Instance);
}
private T Instance;
}
Isn't this all you need? Why should you need to get the T
instance using reflection?
精彩评论