How do attribute classes work?

I haven’t use attributes in my day-to-day work before, but I have read about them.
Also I have done some tests, to back up what I’ll say here. If I’m wrong in any place – feel free to tell me this 🙂

From what I know, attributes are not acting as regular classes. They aren’t instantiated when you create an object that they are applied to, not one static instance, not 1 per each instance of the object.
Neither do they access the class that they are applied to..

Instead they act like properties (attributes? 😛 ) of the class. Not like the .NET class properties, more like in the “one property of glass is transparency” kind of property. You can check which attributes are applied to a class from reflection, and then act on it accordingly. They are essentially metadata that is attached to the class definition, not the objects of that type.

You can try to get the list of attributes on a class, method, property, etc etc.. When you get the list of these attributes – this is where they will be instantiated. Then you can act on the data within these attributes.

E.g. the Linq tables, properties have attributes on them that define which table/column they refer to. But these classes don’t use these attributes. Instead, the DataContext will check the attributes of these objects when it will convert linq expression trees to SQL code.

Now for some real examples.. I’ve ran these in LinqPad, so don’t worry about the strange Dump() method. I’ve replaced it with Console.WriteLine to make the code easier to understand for the people who don’t know about it 🙂

void Main()
{
    Console.WriteLine("before class constructor");
    var test = new TestClass();
    Console.WriteLine("after class constructor");

    var attrs = Attribute.GetCustomAttributes(test.GetType()).Dump();
    foreach(var attr in attrs)
        if (attr is TestClassAttribute)
            Console.WriteLine(attr.ToString());
}

public class TestClassAttribute : Attribute
{
    public TestClassAttribute()
    {
        DefaultDescription = "hello";
        Console.WriteLine("I am here. I'm the attribute constructor!");
    }
    public String CustomDescription {get;set;}
    public String DefaultDescription{get;set;}

    public override String ToString()
    {
        return String.Format("Custom: {0}; Default: {1}", CustomDescription, DefaultDescription);
    }
}

[Serializable]
[TestClass(CustomDescription="custm")]
public class TestClass
{
    public int Foo {get;set;}
}

The console result of this method is:

before class constructor
after class constructor
I am here. I'm the attribute constructor!
Custom: custm; Default: hello

And the Attribute.GetCustomAttributes(test.GetType()) returns this array:
(the table shows all available columns for all entries.. So no, the Serializable attribute does not have these properties 🙂 )
LinqPad Attributes Array

Got any more questions? Feel free to ask!

UPD:
I’ve seen you ask a question: why use them?
As an example I’ll tell you about the XML-RPC.NET library.
You create your XML-RPC service class, with methods that will represent the xml-rpc methods. The main thing right now is: in XmlRpc the method names can have some special characters, like dots. So, you can have a flexlabs.ProcessTask() xml rpc method.

You would define this class as follows:

[XmlRpcMethod("flexlabs.ProcessTask")]
public int ProcessTask_MyCustomName_BecauseILikeIt();

This allows me to name the method in the way I like it, while still using the public name as it has to be.

Leave a Comment