Click here to Skip to main content
Click here to Skip to main content

Tagged as

Quick Overview of C# Attribute Programming

, 23 May 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
Programming with attributes refines and solves some of the difficult development problems we face every day.

Introduction

Attribute programming is a declarative programming model tool that you should keep in your development toolbox. Programming with attributes refines and solves some of the difficult development problems we face every day.

Background

While this article is squarely aimed at beginners, the reader must have an understanding of Reflection in order to comprehend attribute programming.

C# Attribute Programming

When you see this property declaration:

[CustomAttribute]
public string MyProperty { get; set; }

...you should recognize a property declaration that has been 'decorated' with the custom attribute named CustomAttribute.

There are a few things going on here.

First of all, regardless of whether you've ever created your own attributes and used them in your code, you must have seen various .NET Framework-related attributes at certain times in your applications. For instance, if you generate a class from an XSD schema, you'll notice a bunch of attributes attached to almost all the classes in the resultant source file.

Why are they there? What do they do?

At runtime, the .NET Framework investigates those attributes and executes code based on the values those attributes contain.

How does the runtime investigate those attributes?

Reflection.

Now, why use attributes?

Basically, the answer is to simplify your programming and make your code more readable by making more of your code "declarative" in nature. Attribute programming is a declarative programming model.

Attribute programming is effective when some class or class member needs to know something about itself at runtime, and it would make for very inelegant or clumsy code to feed that data to the class or member in any other way.

An example: a class is "hydrated" from a text file at runtime. The name of the text file is known at design time. The class needs a way to know what text file to read at runtime to hydrate itself.

There would be many ways to solve this problem. Among them, a popular one would be to add a property like ContentFileName to the object and hard-code in the name of the file. That would work but it's clumsy and unsightly.

At runtime, that class is going to hydrate itself and become, essentially, data. The name of the file to hydrate with is data. So we're dealing with "data about data", also called "metadata". Whenever you're dealing with metadata, think about attribute programming.

A better solution is to create your own custom attribute. It must inherit from System.Attribute, or another class that itself inherits from Attribute.

A typical custom attribute could look like:

public class ObjectTextAttribute : Attribute
{
} 

Now back in your object code, do this:

public class ObjectTextAttribute  :  Attribute
{
    public ObjectTextAttribute()
    {
    }
    public string ContentFileName  {  get;  set;  }
}

[ObjectTextAttribute(ContentFileName="blah.txt")]
public class TextFile
{
}

You're about halfway done now. You've used attribution to tell that class to hydrate itself from the text file named "blah.txt". Other class definitions could hydrate themselves from different text files.

What's left is the code to parse out those attributes and to do something with them.

Reflection saves the day.

A typical solution for this is to create something like a ReflectOnAttributes method in this class, or better yet, a base class that this class is derived from.

In the ReflectOnAttributes method, you would use reflection code to find and isolate the type of attribute you're looking for, and then do something once you found the value(s).

In this case, we'll scan for the MyCustomAttribute value and then parse out the ContentFileName once found. When we have that, we'll read the text in from that file and assign it to a property in our class.

using System;

using System.IO;
namespace ClassLibrary
{
    public class MyCustomAttribute : Attribute
    {
        public String ContentFileName { get; set; }
    }

    [MyCustomAttribute(ContentFileName = "C:\blah.txt")]
    public class MyCustomClass
    {
        public MyCustomClass()
        {
            ReflectOnClassAttributes();
        }
        public String BodyText { get; private set; }

        private void ReflectOnClassAttributes()
        {
            //inspect for the custom attribute and obtain value of property desired
            object[] classAttrs = this.GetType().GetCustomAttributes(typeof(MyCustomAttribute), true);
            if ((classAttrs != null) && (classAttrs.Length > 0))
            {
                //inspect for the body attribute, this gives our content for the main body
                MyCustomAttribute attr = (MyCustomAttribute)classAttrs[0];
                string fileName = attr.ContentFileName;
                BodyText = File.ReadAllText(fileName);
            }
        }//method
    }//class
}//namespace

There's a lot going on in the (above) code. Let's take it step-by-step.

We start out by defining an attribute class called MyCustomAttribute. It must inherit from the built-in .NET Framework System.Attribute class.

Next we define a class that will use MyCustomAttribute. MyCustomClass is decorated with a citation to "MyCustomAttribute", and provides a value in the attribute constructor to the property ContentFileName. This is where we give the class knowledge about which text file to open and read and hydrate itself.

When the class is instantiated and ReflectOnClassAttributes() is called, the Reflection process interrogates the class declaration and determines what, if any, attributes are declared. When it finds the MyCustomAttribute, it digs into the property and gets its value. Then it simply reads the text file into the BodyText property.

This is a simple example of attribute programming, and you can take it further in your own work. And you should, because attribute programming resolves and refines many of the programming problems we're faced with on a daily basis.

History

Submitted May 22 2012.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Tom R Smith
Software Developer (Senior)
United States United States
I pursued an education in computer science at the University of California at Hayward. I developed a fascination with Borland Turbo Pascal and C++. Then came 'C' and Fortran. Eventually the academics led me to devour Java. My first software development job forced me to rapidly do Visual Basic 6.0. The software career progressed and I found myself consulting to various companies such as Visa, nVidia, Wells Fargo Bank, and others. Along the way I completed work and earned an M.S. degree in, of all things, computer science. I now find myself back in New England, writing C# applications for a medium size company.
 
A.S. Computer Science, Chabot College,Hayward CA 1995
B.S. Computer Science, University of California 2000
M.S. Computer Science, University of California 2003

Comments and Discussions

 
GeneralMy vote of 5 PinmemberSeniorCrispy17-Oct-12 5:05 
QuestionHydrate? PinmemberTed Goulden28-May-12 13:46 
AnswerRe: Hydrate? PinmemberSakshi Smriti28-May-12 18:22 
AnswerRe: Hydrate? PinmemberTom R Smith30-May-12 10:19 
GeneralRe: Hydrate? [modified] PinmemberTed Goulden30-May-12 14:33 
QuestionBenefit? Pinmemberviaducting23-May-12 22:16 
AnswerRe: Benefit? PinmemberZasky24-May-12 0:21 
AnswerRe: Benefit? PinmemberTom R Smith24-May-12 3:02 
AnswerRe: Benefit? PinmemberRoger Alsing24-May-12 3:40 
SuggestionNice article, take codeding guidelines in account Pinmemberpietvredeveld23-May-12 8:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.141022.2 | Last Updated 23 May 2012
Article Copyright 2012 by Tom R Smith
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid