我有一个自定义泛型类,用于在远程接口上调用方法。此类有一个单一的重载方法,Execute
该方法接受远程接口上的Action<T>
或Func<T, TResult>
调用。
public class GenericRemoteProxy<T>
{
public void Execute(Action<T> action) {
// Remoting Magic Goes Here
}
public TResult Execute<TResult>(Func<T, TResult> action) {
// Remoting Magic Goes Here
}
}
使用该类非常简单:
var proxy = new GenericRemoteProxy<ICalculatorService>();
var result = proxy.Execute(x => x.Add(1, 2));
但是,我想更进一步,GenericRemoteProxy
用一个实现实际服务合同接口的类来包装它,这样我的客户端代码只依赖于它关心的实际接口。这与 WCF 中的行为完全相同ChannelFactory
。在 .NET 4.0 中似乎没有本地方式来执行此操作,因此我尝试使用 Castle Dynamic Proxy 来完成它。
我很难弄清楚我应该使用哪种类型的 DynamicProxy,以及如何将目标接口中的调用转换为Actions
然后Funcs
我可以传递给我的GenericRemoteProxy
.
我目前的方法是使用自定义ProxyGenerator
来处理映射。CreateInterfaceProxyWithoutTarget
IInterceptor
var calculatorService =
proxyGenerator.CreateInterfaceProxyWithoutTarget<ICalculatorService>(
new GenericProxyInterceptor<ICalculatorService>(
new GenericRemoteProxy<ICalculatorService>()));
然后,我的拦截器看起来像这样:
public class GenericProxyInterceptor<T> : IInterceptor {
GenericRemoteProxy<T> _proxy;
public GenericProxyInterceptor(GenericRemoteProxy<T> proxy) {
_proxy = proxy;
}
public void Intercept(IInvocation invocation) {
var instance = Expression.Parameter(typeof(T), "x");
var arguments = invocation.Arguments.Select(x => Expression.Constant(x));
var methodCall = Expression.Call(instance, invocation.Method, arguments);
var lambda = Expression.Lambda(methodCall, instance);
if (invocation.Method.ReturnType == typeof(void)) {
var action = //Create an Action
_proxy.Execute(action);
} else {
var action = //Create a Func
_proxy.Execute(action);
}
}
}
我的第一个问题是,这是使用 Castle Dynamic Proxy 完成我所追求的正确方法吗?如果不是,我应该如何将对接口的调用映射到完全不同类型的方法?我读过错误地使用动态代理会导致过多的内存和 CPU 使用,所以我想尽可能避免这种情况。
我的第二个问题是,如何将我的 LINQ 表达式转换为正确的Action<T>
或Func<T, TResult>
我的代理所期望的?在调试视图中,lambda 似乎是正确的(它显示为x => x.Add(1,2)
)。但是当我尝试传入lambda.Compile()
该Execute
方法时,我被告知该方法有一些无效的参数。