Ayende posted
7 different interception approaches for AOP in .NET. Here's one more...
...well, actually, it's a "cheat's way" to do interception. But, it's has proved to be useful in the real world and it avoids all of the disadvantages mentioned in Ayende's post.
It is "the interception you do, when you're not doing interception"(*). It simply means that you write your property getters and setters in such a way that "interception" is built right into the code. Here's an example from
Mindscape LightSpeed:
public string DisplayName
{
get { return _displayName; }
set { Set(ref _displayName, value, "DisplayName"); }
}
The Set method can do whatever is required, both before and after it sets the actual value.
Pros:
Simple, understandable, debuggable. Can still use "new" to create objects (unlike some alternatives).
Cons:
Only works for properties. While properties are the
main place where interception is required (at least in ORMs and
related functionality) some people do want interception on methods too.
Another disadvantage is that you have to put the property name into the setter method. While this is not too bad if your objects are generated (just re-generate if names change) it's still a bit ugly to have string names in the code. I'm particularly uncomfortable with it if anyone is likely to rename the property (using Resharper's Rename feature for instance) while forgetting to also change the string name in the property setter. And, given Murphy's Law and human nature, forgetting probably
is likely.
Property Name Solutions
What if you don't like that property name sitting inside the setter methods?
Rocky Lhotka put together a solution to the property naming problem. The solution is based framework code crawling back up the stack to find the property setter. In my own tests, that can be slow and, as Rocky notes, it can be
broken by method inlining.
I have put together an alternative solution, which does not suffer from those drawbacks. It lets you write the code above like this (note that the property name string is not inside the setter method any more):
public string DisplayName
{
get { return _displayName; }
set { Set(ref _displayName, value); }
}
It works by leveraging the fact that the first parameter is a ref parameter. With a bit of managed C++, you can convert that ref param into a managed pointer. Then you can look at how far "into" the object it points, and use that to identify the property. (Technically, it identifies the field. But, if each field is used by one property, then we can easily associate field names with property names.)
Note that the managed C++ code is pure .NET code, marked as "
unsafe" so that it can use pointers. It has to be written in C++, not C#, because while C# can use pointers, it cannot create one from a ref parameter.
You can find a full working implementation
here. Please note that I am not a C++ developer. This was the first (and probably the last) managed C++ that I have written! While I have undertaken a number of tests to check the validity of this appoach, the fact remains that I'm not experienced in managed C++. Use at your own risk. Please post any questions below.
Update, Feb 08: I've posted an updated, re-written version
here.
(*) Austrialian and New Zealand readers may recognise the theme in naming this post. It's based on
Claytons, marketed many years ago as "The drink you have when you're not having a drink."