Saturday, November 05, 2005

Attribute usage

Attributes in .net are controversial. NUnit's attribute usage has been praised. Conversely, the NanoContainer implementation has been criticized*. So what is the difference? What makes one usage successful and another a failure?

In an email exchange, Martin Fowler expressed to me (roughly, I didn't save the email, so I can't quote) that a major problem with using attributes is that they can cause coupling issues. For example, adding the NanoContainer attribute will add a dependency to NanoContainer within your project. Compared this to the NUnit implementation, NanoContainer is much more intrusive. The NUnit attributes are used on the test classes (and test methods). This requires no change to your existing classes and adds no dependency on NUnit within your existing classes.

Attributes are often used as class markers, which can also be done by implementing an interface. However, if you need to mark a method or property an attribute is a great candidate. I think this is another reason that NUnit was so successful concerning attributes. Conceptually, without attributes a class could implement a ITest, but which methods would be run as test methods?

So, when would you use attributes in your code? Currently, I'm working on a project where we have an object that represents several database tables. Additionally, these tables contain data that needs to be transformed. The transformation rules are contained in a database that the business analysts maintain. The business analysts are intimately familiar with the database tables and columns. Therefore, the transformation rules are written using the database table and column names as identifiers.

Unfortunately, the table.column identifier is not very descriptive. For readability we chose to create readable properties on the object and simply add a attribute that contains the table.column identifier. The transformation engine can load the rules from the database, use reflection to find the corresponding property, and transform the value.

public class Foo
{
[Identifier("AMfD.b12F")]
public string Bar
{
get { return bar; }
}
}

With this implementation, the value of the property can be easily accessed using reflection and the identifier or simply by accessing foo.Bar. Conceptually, this could be done with some mapping code also, but this seemed to be the simplest thing that could possibly work.

* Personally, I like the attribute usage in NanoContainer also.
Post a Comment