Hello all,
I ran in to an issue with using a proxied object as a key in a
hashtable. I've included some code that works around the issue, but it
doesn't feel like the best way to handle it. As a minor point of
discussion using equivilant Castle.DynamicProxy2 code passes these
tests.
If anyone would like I have this code wrapped up in a VS20008 solution
that I can post if needed.
Here some test code that demos the problem.
using System.Collections;
using LinFu.DynamicProxy;
using NUnit.Framework;
namespace LinfuEquals
{
[TestFixture]
public class LinfuEqualsTests
{
[Test]
public void Failing_Equals_Test()
{
ProxyFactory factory = new ProxyFactory();
Entity entity = new Entity();
BadEnitityInterceptor interceptor = new
BadEnitityInterceptor(entity);
Entity proxy = factory.CreateProxy<Entity>(interceptor);
Assert.IsTrue(proxy.Equals(proxy), "The objects are not
equal");
}
[Test]
public void Passing_Equals_Test()
{
ProxyFactory factory = new ProxyFactory();
Entity entity = new Entity();
GoodEnitityInterceptor interceptor = new
GoodEnitityInterceptor(entity);
Entity proxy = factory.CreateProxy<Entity>(interceptor);
Assert.IsTrue(proxy.Equals(proxy), "The objects are not
equal");
}
[Test]
public void Why_Does_This_Matter()
{
ProxyFactory factory = new ProxyFactory();
Entity entity = new Entity();
BadEnitityInterceptor interceptor = new
BadEnitityInterceptor(entity);
Entity proxy = factory.CreateProxy<Entity>(interceptor);
Hashtable table = new Hashtable();
table.Add(proxy, new object());
Assert.IsTrue(table.ContainsKey(proxy), "The hash does not
contain the key");
}
}
internal class GoodEnitityInterceptor : EnitityInterceptorBase
{
public GoodEnitityInterceptor(object target) : base(target){}
public override object DoInvoke(InvocationInfo info)
{
if (
info.TargetMethod.Name == "Equals")
{
return info.Arguments[0].Equals(_target);
}
return info.TargetMethod.Invoke(_target, info.Arguments);
}
}
public class BadEnitityInterceptor : EnitityInterceptorBase
{
public BadEnitityInterceptor(object target) : base(target){}
public override object DoInvoke(InvocationInfo info)
{
return info.TargetMethod.Invoke(_target, info.Arguments);
}
}
public abstract class EnitityInterceptorBase : IInvokeWrapper
{
protected readonly object _target;
protected EnitityInterceptorBase(object target)
{
_target = target;
}
public abstract object DoInvoke(InvocationInfo info);
public void BeforeInvoke(InvocationInfo info) { }
public void AfterInvoke(InvocationInfo info, object
returnValue) { }
}
public class Entity
{
public virtual string Name { get; set; }
}
}