Sunday, December 11, 2005 

AOP in C#

There is a nice framework for AOP freely available and discussed here: NAspect AOP engine. It's actually very very similar to something I dreamed :-) to build and never ventured to.
I'm somewhat in a hurry, so I'll have to get back to this later, but if you look at the example given, you'll see you need to go through a factory. This is necessary because you won't get back an instance of the type you request, but of synthesized subclass. That's at odd with source code generators, of course, but that would be another long story. Of course, it would be much nicer if we could override the global operator new in C#, but we can't. However, C# is evolving into an interesting language (leaving aside my distaste for garbage collection...) and we could end up with something interesting in the future. More on this another time...
Cosa ne pensa invece dell'AspectC++?
NAspect author here.

The use of factories might look messy at first, but they come with great posibillities,
eg. we could add DI/IoC configuration to specific types in the factory.
we already do this in NFactory which is a DI/IoC container which go through NAspect when the instances are created.

Also by not overriding the new operator we keep the AOP clean in a OO way,
your original type is still the same, no unexpected beaviors are introduced into it.
and we can also apply different AOP configurations to the same type in the same process which I think we are the first to do , atleast in .NET.

meaning, we can apply persistence aspects to a "Customer" class , while in another usecase in the same app/process we might apply some serialization aspects to the same "Customer" type (so you get two subclasses of customer).

this would be impossible if the original type was modified/replaced.

The factory can also be used to "interface wrap" existing instances by creating a proxy which
only implements the same interfaces as the wrapped instance and then redirects every call to it through the aop engine into the real instance.

so factories are not all bad :-)
Roger, thanks for your comment! It's a good opportunity to explain my thoughts better. First of all: the original posting, and everything that follows here, it's not a criticism on your work: you did a great work, and given C# as it is today, factories are basically unavoidable when you want to intercept object creation. However:
- factories are a syntactic nuisance. C# syntax is already forcing us to use "new" way too much (compared, for instance, to C++). That may seem just a minor flaw, but it's not. I believe programmers should be able to create their own abstractions (classes) and clearly express their thoughts using those abstractions. A plethora of "new" just gets in the way of clean code, and unfortunately factories tend to be even worse...
- factories don't mix well with code generators, and the Visual Studio form editor is a code generator. If you want to inject aspects in controls defined at design time, you're out of luck (unless you want to tweak generated code).
- factories don't mix well with component-oriented programming. You need to change the source code to go through the factory. You don't necessarily have source code for the components you use [in process], and even if you do, you may not be willing to modify third-party source code.
Is there a way out of this? Well, maybe, but we need a better support inside the language. C# (.NET actually) is already providing a nice support for "method interception". We can dynamically create a derived class, inject aspects into that class, and use polymorphism. We can use the transparent/real proxy stuff. Etc. But this requires a way to intercept object creation. Today we've got to use factories. Now, in C++ you can override operator new at the type level, or at the global level. We usually do that to create custom allocators, as user-defined operator new can only provide raw memory: as such, it would be useless in the .NET environment.
However, we could borrow on the same idea. In .NET/C#, overriding operator new could take place at the application domain level, so the redefined operator new would be called also for third-party components loaded in process. A user-defined operator new would not be concerned with providing raw memory: it could be concerned with returning the actual type to be created. Therefore, it could have a syntax like:
System.Type operator new( System.Type )
or something like that. We could then easily intercept object creation (based on a configuration file or whatever) and return the intercepting type (a dynamically created class, or a proxy, or whatever). An instance of that type would then be created instead of the original type.
Now, about having different aspects injected in different contexts. If we want to handle this transparently from the user (therefore moving all this stuff in the configuration file) we could simply look at the call stack inside operator new, and understand (again from the config file) which aspects [and therefore type] are needed. Another alternative would be to support multiple, overloaded operators new, like in C++, where you can define an operator new with additional parameters and call it like:
T* ptr = new( p1 ) T( v1, v2 ) ;
in our case, p1 would be the context, or whatever is needed to decide which aspects we need. As you can guess, I like the idea of looking at the call stack, because it keeps my code clean and moves all the interception stuff into an external configuration file.
Anyway, this is just wishful thinking :-). I'm not expecting anything like that, anytime soon. So, whether I like them or not, I guess factories are here to stay :-)).
Post a Comment

<< Home