2

我有一个自定义泛型类,用于在远程接口上调用方法。此类有一个单一的重载方法,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来处理映射。CreateInterfaceProxyWithoutTargetIInterceptor

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方法时,我被告知该方法有一些无效的参数。

4

0 回答 0