代码之家  ›  专栏  ›  技术社区  ›  driis

castle dynamicproxy:代理接口时如何代理等于?

  •  10
  • driis  · 技术社区  · 15 年前

    我需要使用castle dynamicproxy通过向proxygenerator.createInterfaceProxyWithTarget提供接口的实例来代理接口。我还需要确保对Equals、GetHashCode和ToString的调用会命中我正在传递的具体实例上的方法,但我无法使其正常工作。

    换句话说,我想打印这个小样本 True 两次,而实际上它打印 True,False :

    using System;
    using Castle.Core.Interceptor;
    using Castle.DynamicProxy;
    
    public interface IDummy
    {
        string Name { get; set; }
    }
    
    class Dummy : IDummy
    {
        public string Name { get; set; }
    
        public bool Equals(IDummy other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return Equals(other.Name, Name);
        }
    
        public override bool Equals(object obj)
        {
            return Equals(obj as IDummy);
        }      
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            var g = new ProxyGenerator();
            IDummy first = new Dummy() {Name = "Name"};
            IDummy second = new Dummy() {Name = "Name"};
            IDummy firstProxy = g.CreateInterfaceProxyWithTarget(first, new ConsoleLoggerInterceptor());
            IDummy secondProxy = g.CreateInterfaceProxyWithTarget(second, new ConsoleLoggerInterceptor());
    
            Console.WriteLine(first.Equals(second));         
            Console.WriteLine(firstProxy.Equals(secondProxy));
        }
    }
    
    internal class ConsoleLoggerInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("Invoked " + invocation.Method.Name);
        }
    }
    

    用动态氧气可以吗?怎样?

    2 回复  |  直到 14 年前
        1
  •  12
  •   Krzysztof Kozmic    15 年前

    这有点棘手。 Take a look at documentation 关于代理如何工作。接口代理包装对象并拦截对指定接口的调用。自从 Equals 不是该接口的一部分,对equals的第二个调用是比较代理,而不是它们的目标。

    那么是什么为第二个提供了实现 等于 打电话?

    代理只是实现 IDummy 接口。和任何类一样,它也有一个基类,这是 等于 会被调用。默认情况下,此基类 System.Object

    我希望你现在能明白这是怎么回事。这个问题的解决方案是告诉代理实现一些支持代理的基类,这些基类将调用转发到代理目标。其实现的一部分可能如下所示:

    public class ProxyBase
    {
        public override bool Equals(object obj)
        {
            var proxy = this as IProxyTargetAccessor;
            if (proxy == null)
            {
                return base.Equals(obj);
            }
            var target = proxy.DynProxyGetTarget();
            if (target == null)
            {
                return base.Equals(obj);
            }
            return target.Equals(obj);
        }
        // same for GetHashCode
    }
    

    现在,您只需要指示代理生成器将这个基类用于您的接口代理,而不是默认代理。

    var o = new ProxyGenerationOptions();
    o.BaseTypeForInterfaceProxy = typeof(ProxyBase);
    IDummy firstProxy = g.CreateInterfaceProxyWithTarget(first, o);
    IDummy secondProxy = g.CreateInterfaceProxyWithTarget(second, o);
    
        2
  •  0
  •   Dougc    14 年前

    在你的样本中;你的班级 Dummy 器具 IDummy ,但也提供了更具体的 Equals . krzysztof建议的另一种选择是通过让它实现,将这个方法拉入到您的接口中。 IEquatable<T> 例如:

    public interface IDummy : IEquatable<IDummy>
    {
        string Name { get; set; }
    }
    

    这样,您的界面现在包含了更具体的 等于 覆盖,这意味着生成的代理将根据需要代理对目标的调用。

    显然,这并不能解决整个问题,只允许代理将呼叫转发到 Equals(IDummy) 而不是 Equals(object) (或) GetHashCode 就这点而言)。