views:

112

answers:

2

Hi,

I've asked this in the NHibernate forumns but I think this is more of a general question. NHibernate uses proxy generators (e.g. Castle) to create its proxy.

What I'd like to do is to extend the proxy generated so that it implements some of my own custom behaviour (i.e. a comparer). I need this because the following standard .NET behaviour fails to produce the correct results:

//object AC is a concrete class
collection.Contains(AC) = true

//object AP is a proxy with the SAME id and therefore represents the same instance as concrete AC
collection.Contains(AP) = false

If my comparer was implemented by AP (i.e. do id's match) then collection.Contains(AP) would return true, as I'd expect if proxies were implicit. (NB: For those who say NH inherits from your base class, then yes it does, but NH can also inherit from an interface - which is what we're doing)

I'm not at all sure this is possible or where to start. Is this something that can be done in any of the common proxy generators that NH uses?

A: 

This kind of behavior is possible with LinFu.DynamicProxy, but you would have to replace the interceptor provided by NHibernate with your own custom interceptor that delegates it calls back to the original interceptor:

var yourProxiedInterfaceInstance = ...

// Get the Interceptor that NHibernate uses

var proxy = (IProxy)yourProxiedInterfaceInstance;

var interceptor = proxy.Interceptor;

// You'll need to create a decorator class around the IInterceptor interface
var yourInterceptor = new SomeCustomInterceptor(interceptor); 

// Replace the interceptor here
proxy.Interceptor = yourInterceptor;

This is pretty easy to do with LinFu since every proxy instance that it generates requires an interceptor. If you change the interceptor, then you can automatically change a proxy's behavior. I hope that helps.

plaureano
Thanks for the tip. At least now I know what I want is not totally off the wall. I'll look into LinFu.
Graham
A: 

With Castle DynamicProxy you have few choices.

First is to provide the IComparer<T> as one of additionalInterfacesToProxy when creating the proxy. The interface will have no actual implementation to proceed to, so you need to provide an interceptor that instead of calling Proceed will provide the actual logic for the methods.

Alternatively you can provide a mixin, which implements the required interface and provides the logic you need. Notice you most likely will need to pass the mixin reference back to the proxy or its target.

Third option, available only for interface proxies is to set the base class proxyGenerationOptions.BaseClassForInterfaceProxy = typeof(SomethingImplementingComparer);

Krzysztof Koźmic
Krzysztof, the third option - I assume this a Castle setting? I can't find it in the NH documentation anywhere.It certainly seems like the easiest option if I can hook it up properly. Not quite sure how to configure Castle within NH yet!
Graham
yes, it's part of Castle's settings. To wire NHibernate up, I think you'd have to supply your own `ProxyFactoryFactory` and `ProxyFactory`. I'd start by looking at what's in `NHibernate.Bytecode.Castle.dll`
Krzysztof Koźmic
Krzysztof, went for the third option but it's not working as I'd expect. The proxy generated by castle does indeed cast to the base class I specified, but it doesn't fire the base class comparer UNLESS I cast the proxy to the base class. It looks like Castle is "proxying" the base class as well, not using the base class as the proxy for the interface. Is this correct?
Graham
No. Looks like the default comparer will ignore the fact that proxy implements the interface and still compare references. I'll need to provide custom comparer to the list I think
Krzysztof Koźmic
So this will be a change to Castle at some point in the future? Ok, thanks anyway then. I'll look out for it - for reference, I've tried it with IComparer<T> and IComparable<T> - neither made the proxy hit the base class unless I cast the proxy first.
Graham