10

Castle DynamicProxyを使用して、インターフェイスのインスタンスをProxyGenerator.CreateInterfaceProxyWithTargetに提供することにより、インターフェイスをプロキシする必要があります。また、Equals、GetHashCode、およびToStringの呼び出しが、渡した具象インスタンスのメソッドにヒットすることを確認する必要がありますが、それを機能させることはできません。

つまり、この小さなサンプルを2回印刷したいのですが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への2番目の呼び出しは、ターゲットではなくプロキシを比較することです。

Equalsでは、2番目の呼び出しの実装を提供するものは何ですか?

プロキシは、IDummyインターフェイスを実装するもう1つのクラスです。他のクラスと同様に、基本クラスもあり、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 に答える