KnowDotNet Visual Organizer

Take advantage of .NET's Built in Attributes

Easing Version Promotions

by William Ryan
Print this Article Discuss in Forums

There are so many cool things about .NET that it's hard to say what the 'coolest' feature is.  As a matter of fact, it'd be hard to identify the Top 5.  If I were to create a list though, Attributes would have to be included in any list I created.

I wrote an
introduction to attributes a few weeks ago, but the subject is something I find so absolutely cool that I want to write as much as I can about it.

So what exactly are Attributes and Why should I use them?

Stated simply, attributes are a mechanism for providing additional information about your code.  They in turn emit metadata about your code and this code can be used/interrogated at runtime using Reflection.  So unless you are familiar with Reflection, you are probably saying "So what?".   Here's what:

When you create a class, you define its methods, properties and events.  You give each of these scope and in some instances a data type.  So, if you create a method as 'private', at runtime it will have no visibility outside of that class.  On the other hand, if you create it as public, friend, protected etc, you will have different levels of visibility.  Imagine what OOP would be like if you only had one scope level for everything?  Yes, it would be much less cool.  So clearly you can see that being able to modify scope is a huge benefit.  That's where attributes shine, you see, they allow you to add much more information about your class(es) and have that available at run-time.   So instead of just being able to tell your program and the world that something is Public or Private, you can tell it anything you want to about that class.  If you read my article referenced above, I point out how attributes can replace ugly compiler directives.  As such, you can indicate whether or not a piece of code should be 'live' or not by using a built in attribute.  The alernative of course is that you can use a compiler directive, but there are a lot of things that don't lend themselves well to that model.  

.NET provides an attribute called Serializable.  If a class is marked with this attribute, it means that it can be serialized or persisted as long as it implements a IFormatter interface.  So I may have a Person object and I use the Serializable attribute with it.  That means that I could conceivably use Binary Serialization, SOAP Serialization and any other type I wanted including SomeSerializationBillJustMadeUp.

In the past, how would you do this?  Perhaps you'd write your own method called Serialize and include it any time you wanted your object to be able to be serialized.  Think of how much code this would take?  And how could you turn it on or off?  A better example might be a class that can print.  Let's say that you are writing a program for a prison or a bank.  As such, you might want only a few people with high levels of accountability to be able to print checks or print release notices.  What would you normally go through to prevent this?  A typical scenario would be to have a permission component in your program and disable certain screens or functions based on who is in the system.  It would take some work, but it certainly wouldn't be impossible.  On the other hand, you could define some custom attributes, and use network credentials to authenticate who the user is and what they can and can't do.  And you can do this with a lot less code in most instances. As a matter of fact, Attributes are the centerpiece of .NET's Declarative Security model.

But there are many other uses for them, and don't require such a thorough understanding of both Attributes and Declarative Security.  Well, let me show you one simple yet helpful way to use an attribute.

Many programmers have the habit of Commenting out code that they aren't using when they modify it or improve it.  After all, if it used to work, you want the ability to quickly revert to it if your new code all of a sudden starts acting buggy.  In addition, you'll often leave it in there for reference purposes, commented or not.  If you choose not to comment it, you'll usually just remove any code that calls it.  The problem is that this type of code tends to hang around well after it is of any possible use.  You just aren't sure when it's no longer necessary, and after a bunch of re-writes of version upgrades, it does nothing but confuse (the whole problem leaving it in was supposed to minimize) people.  In other more structured companies, you often work on multiple versions simultaneously.  Often times, you'll branch out of one project and use it to build the next version with.  So let's say that we just branched out our new 100,000 line program and we are begging working on the new version.  There's tons of code in there that we begin changing, but many of use leave some old blocks in there because we wanted to remember core logic.  Moreoever, some of the modifications are simply tweaked implementations of identical blocks with old names.  Then, a few months later, we are ready to ship the project.  At this point, we have tons of commented out code and methods that aren't being called.  None of the current team worked on the last version so none of us are really sure what is ours and what was left from previous builds.  We were pretty organized so we made some datetime notes on each block we commented out, but there's a ton of code out there that isn't being used or commented out.  The boss comes by and sees how much code isn't necessary and he decides that he wants it all out of the system.   At that point, everyone on the team would have a whole LOT of Find and Replacing in their future.  But, since all the code wasn't just commented, we really have to be careful not to whack good code.  So at best, this process is going to be slow, inconvenient and error prone.

Let's say on the other hand, we were .NET programmers and knew about Attributes.  Starting at the earliest builds, we knew about the Obsolete attribute and marked our code accordingly. This allowed us to refer to the code and provided every benefit of the old 'Comment Out' or 'Remove all References' method and took the same or less work to implement.  The boss makes the same announcement that day.  All we'd have to do is decide who was going to clean up what modules, go to our TO DO list, click on each one, and remove each block.  There is another boolean which tells the compiler to treat code with the Obsolete Attribute as an error and not allow a clean build.  You can leave this off until 'cleanup' phase and then go back, turn it on and verify that everything was removed correctly.  Or you could leave it on perpetually (not recommened) and know that you can't call any code marked obsolete.  If you've ever worked on a large product that was going through a version upgrage, and were some junior programmer who got stuck with all of the grunt work, you'll know how absolutely cool this can be.  Remember too that Obsolete is just one of many attributes .NET provides us, and there's no limit to what they can do because you can write your own!

To show you how absolutely easy Obsolete (and Attributes in General) are to implement, look at the code below:


Public Sub DoSomething()
         Dim i as Integer
         Dim j as Integer
         j+=1
         MessageBox.Show(j.ToString)
End Sub


'The upgrade calls for .20% tax to be added to the computation

Public Sub DoSomething(ByVal TaxRate as Long)
         Dim i as Long
         Dim j as Long
         j+=1
         j+=(j *TaxRate)
         MessageBox.Show(j.ToString)
End Sub


Imaging this happening 50+ times in different functions and that we are going to leave the DoSomething in and not call it, or we'll Comment it out.  

Now, using Attributes you'd simply do this:

<Obsolete()> _
Public Sub DoSomething()
         Dim i as Integer
         Dim j as Integer
         j+=1
         MessageBox.Show(j.ToString)
End Sub


The next time I opened up the project, everything marked Obsolete would appear in my ToDo List, so I could just click on it and get rid of it.  Moreoever, like I mentioned, we could change the boolen and stop this from compililng.

Yes, a mere one line of code can help you track down and identify code blocks you don't want to use.  Moreover, it won't let you call Obsolete methods, so you wouldn't have to worry about accidentally leaving in a call to the obsolete method.  Finally, you can prevent the build from happening....so your boss could announce a 'final' date where everything needs to be cleaned up and there would be an easy mechanism to implement this.

This is a description of Attributes at it's absolute simplest.  In my next article Advanced Attributes, I'll show you some more sophisticated and useful ways to take advantage of one of .NET's coolest features.

Writing Add-Ins for Visual Studio .NET
Writing Add-ins for Visual Studio .NET
by Les Smith
Apress Publishing