I’ve blogged in the past about compile-time aspect oriented programming in C#. Please read that first, then come back, for this to make sense.
In summary: we want to be able to define aspects, write aspect-like code once, and have it automagically added to any class that uses that aspect.
After a lot of research, it seems like the best, easiest, and most flexible (albeit not-100%-automagical) way to do is is to implement aspects as an interface/implementation pair and inject them with Ninject.
Again, what does this mean?
- Each aspect is defined by an interface. This gives us compile-time checking on which class implements which aspects. In our case, let’s imagine a (game-like) aspect like
ILiving(for creating entities that have health and are alive or dead).
- Each aspect is implemented in one interface-consuming class. This means the code for each aspect is in one place. In our case, we would have an
LivingImplclass that implements
- Aspects are injected into every class automatically. No need to use a code weaver, post-build process, or anything else; just a simple (Ninject) kernel and a single
- Classes implement interfaces, and redirect calls to *Impl instances. Our
Playerclass would also implement
ILiving, and redirect calls to an
- Aspects can be customized. Our
LivingImplclass might define
Health > 0. Say we wanted to implement a zombie, which is living as long as it has health above -100. Since
Zombiehas an instance of
ILiving, simply change the code to contain the new definition of
IsAliveinstead of returning
Anyway, since this is practically possible, I plan to try this out in a future project. I’ll keep you posted on how it goes. It looks very exciting! My proof of concept using Ninject was very quick to be implemented, and worked like a dream.
One minor detail: Ninject uses constructors to pass in the implementations of interfaces. If you have a large number of aspects, and you don’t like using a huge constructor, you can always use Property Injection to inject via properties. But again, do you really want to expose a getter/setter for your property? Probably not; constructors are the way to go (and they signal dependency to the reader too).
And of course, you can always use dynamic classes and simply accumulate aspects that way; but I really prefer strong compile-time checking.