public class BasicClassWithIBarProxy : BasicClass, IBar //inherit from our subject and add interface {
private BasicClass m_Subject; //encapulate our subject
private BarImplementer m_Bar; //encapsulate our implementer
//override method and broker the call to our subject.
public override int Method() {
Console.WriteLine("BasicClassProxy:Method");
return m_Subject.Method();
}
public void Go() { //needed for IBar
m_Implementer.Go();
}
//allow our subject to be given to us upon construction
public BasicClassProxy(BasicClass _Subject, BarImplementer _BarImplementer) {
m_Subject = _Subject;
}
}
To make this generic one could say that my dynamic proxy generation went through the following steps
-
Iteratre through interface implementor pairs
-
Add interface to class declaration
-
add parameter to constructor
-
encapsulate the class
-
iterate through the methods of the interface adding method redirection to encapsulated implementor
-
iterate through each event creating a quick handler that bubbles the event
As one can see the generated class is simply a proxy of BasicClass that also aggregates IBar passing the method calls off to an implementor object who knows how to handle the calls received for IBar. You will notice that in this case I am not passing context, I did this for simplicity of the example the real server does pass context information to the implementor. This is a wonderful way of performing my aggregations but as I knew would happen I ran into a case where the code that I needed to aggregate was not mine nor did it support an interface. I at this point decided to support multiple base class base aggregation.
I am quite sure the astute reader just thought “wait this is a single inheritance based environment“. Well actually the very astute reader probably knows that there are numerous simulated multiple inheritance patterns available :) I chose to use David Esparza-Guerrero's pattern listed here http://www.codeproject.com/csharp/smip.asp to do my simulated multiple inheritance. To make a long read short (though I recommend reading it)... it uses implicit operations to allow for the simulation. Note that this aggregation based method only supports public contract MI not true MI within the object itself (although with a bit of hacking with reflections to avoid scope issues ... actually just no ... don't do that :))
Using such a methodology becomes a _bit_ more interesting as we are not assured to be successful every time! The major culprit here is public variables (the astute reader may also point out that non-virtual methods also are a problem). Public variables are a nightmare because there is no way of intercepting them to pass through the call to the subject object. While its quite easy to say “use properties“ it is more difficult in practice when you do not necesarily know what you will be operating nor will you control everything you operate on. Due to this I decided to take a best stab at it.
The first bit that I added was detection if the subject classes had public variables, this helped alot by throwing them out immediately I would allow the base (primary subject) to have public variables but not the mixins ...
And finally ...
We are to my fringe cases!
What if multiple classes have public variables?
Barf an error
What if the base class did NOT have public variables but one of the mixins did?
Well I supported it, my code at this point will actually change out the subject to be the mixin that has public variables and will treat the original class to be proxied as if _it_ were a mixin, externally the behaviors are the same.
What if the classes have non-virtual methods?
Well I just complain about it I still generate the class but I generate messages ...
I would love to hear some general thoughts from other people who have dealt with the same issue and their methods of handling this.
Cheers,
Greg