10

我需要使用 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);
    }
}

这可能与 DynamicProxy 吗?如何 ?

4

2 回答 2

14

这有点棘手。查看有关代理如何工作的文档。接口代理包装一个对象并拦截对指定接口的调用。由于Equals不是该接口的一部分,因此对 equals 的第二次调用是比较代理,而不是它们的目标。

Equals那么是什么为第二次调用提供了实现呢?

代理只是另一个实现你的IDummy接口的类。与任何类一样,它也有一个基类,这Equals是被调用的基类。这个基类是默认的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);
于 2010-06-03T22:37:15.050 回答
0

在您的样本中;你的类Dummy实现IDummy了,但也提供了一个更具体的覆盖Equals。Krzysztof 建议的替代方法是通过实现此方法将其拉入您的界面IEquatable<T>,例如:

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

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

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

于 2011-07-06T12:13:09.777 回答