An example of .NET attribute usage

Published March 17, 2005
Advertisement
People often ask what the point of attributes is, and how they can be used effectively. I thought I'd talk a bit about one of the ways we use attributes in our apps, and as a bonus give you a few details on our boot process.

A bit of background
In our apps, all of the different components are divided into groups such as 'Shutters' and 'Services'. Services are the bits of code that sit in the background and listen to telephony events, or manage database connections, or keep track of contact lists, and so on. Shutters are the GUI components. Shutters tend to rely on services to figure out exactly what needs to be displayed. For example, the contact shutter asks the contact service for a list of contacts to display. Each of these components consists of a primary class, plus various helper classes as necessary.

Because shutters depend on services, it makes sense to initialize the services before initializing the shutters.

Application startup
We want our application startup code (known as the 'boot manager') to be as generic and reusable as possible - it shouldn't have to know about the details of each particular shutter or service, and of course the lists of necessary shutters and services shouldn't be hard coded. So the question is, how can we ensure that the services are started before the shutters are initialized, while maintaining genericity? Wouldn't it be nice if, say, we could pass an assembly to the boot manager, and have it automatically initialize any services and shutters inside the assembly? How can we pull this off?

Attributes to the rescue!
As mentioned above, each component consists of a primary class. These primary classes contain the initialization code that needs to run when the application starts up. So let's take each one of these primary classes and tag it with an attribute indicating that it is a service or a shutter. We'll call this attribute 'Bootable'.

[Bootable(BootableType.Service)]public class MyImportantService{   ...}[Bootable(BootableType.Shutter)]public class MySuperImportantShutter{   ...}

On startup, assemblies get passed in to the boot manager, which examines the assemblies for any classes with these attributes. It groups them into services and shutters, and initializes them one after another.

Problem solved! We can now be sure that services are initialized first. But this leads to another problem - dependencies between services. It is quite conceivable that one service might depend on another; the contacts service mentioned above might use the database service to talk to the DB where the contacts are stored. We need a way of ensuring that the database service is initialized before the contacts service. At this point we have to make the assumption that the programmer writing a service knows what other services it depends on. Given this, all that is needed is a 'Prerequisite' attribute that indicates which other services need to be running before the service in question can start.

[Bootable(BootableType.Service)][Prerequisite("MyOtherService")][Prerequisite("GDNetJournalService")]public class MyImportantService{   ...}[Bootable(BootableType.Service)]public class MyOtherService{   ...}[Bootable(BootableType.Service)]public class GDNetJournalService{   ...}

After the boot manager builds the lists of services and shutters, it then orders them based on prerequisites, and starts them as above. (If our intrepid programmer decides to code in a circular dependency, he will be greeted with an exception on startup)

So there you have it - a way of using attributes to ease the pain of initializing your application.
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement