Я должен использовать замок DynamicProxy для проксирования интерфейса путем обеспечения экземпляра его к ProxyGenerator. CreateInterfaceProxyWithTarget. Я также должен удостовериться, что вызовы к Равняются, 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? Как?
Это немного сложно. Посмотрите в документации, как работают прокси. Интерфейсные прокси оборачивают объект и перехватывают вызовы к назначенному интерфейсу (интерфейсам). Поскольку Equals
не является частью этого интерфейса, второй вызов equals сравнивает прокси, а не их объекты.
Так что же обеспечивает реализацию второго вызова Equals
?
Proxy - это просто другой класс, реализующий ваш интерфейс IDummy
. Как и у любого класса, у него есть базовый класс, и это базовая реализация Equals
, которая вызывается. Этот базовый класс по умолчанию System.Object
Надеюсь, теперь вы понимаете, к чему это приведет. Решение этой проблемы заключается в том, чтобы сказать proxy реализовать некоторый базовый класс, знающий прокси, который будет перенаправлять вызовы на цель прокси. Часть его реализации может выглядеть так:
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);