Getting started with attributes in .NET– part II

In the previous post, we’ve started looking at how we can use attributes to improve the metadata of a type. Even though we’ve looked at some attributes and seen how the C# compiler reduces the required typing by allowing us to skip the Attribute suffix, I didn’t really got into details about how attributes are defined.

In practice, an attribute is always a class. CLR compatible attributes are represented by classes which derive, directly or indirectly, from the Attribute class. Whenever we apply an attribute to a type or member, the compiler needs to create an instance of that type. In fact, you’ve probably noticed that the syntax used for applying an attribute is similar to a constructor call (without the new operator). C# allows us to use a special syntax for setting up properties too. The next snippet starts by creating a new custom attribute and shows how you can initialize its properties in C#:

internal class DumbAttribute:Attribute {
    public DumbAttribute(string name) {
        Name = name;
    }

    public String Name { get; private set; }
    public String MoreInfo { get; set; }
}
[Dumb("Luis", MoreInfo = "Say something!")]
class Program {

As you can see, we’ve started by passing the String used for initializing the private name field required by the constructor (since I didn’t specify a default constructor, there’s no way to create a new DumbAttribute instance without passing at least a string!). After that, I’ve initialized the MoreInfo read/write property by using a pair name/value. The docs use different names for identifying these different types of parameters:

  • Positional parameters represent parameters passed to the constructor (notice that the order is important here!)
  • Named parameters are always defined after positional parameters and allows us to initialize public fields or properties.

When we don’t need to pass any parameters to an attribute instantiation, then we can simply omit the the parameters like we did in the samples shown in one of the last posts:

[Serializable]
public class Student {

In C#, there are several ways for us to apply several attributes to a type or member. We can wrap each attribute with its own square brackets ([ ]) or we can use a single pair of square brackets and separate each attribute with a comma. The next snippet shows both approaches:

[Serializable]
[Dumb("Test")]
public class Student {

[Serializable, Dumb("Test")]
public class Student {

Before ending, there’s still time for a couple of observations about custom attributes:

  1. constructor parameters, fields and properties are restricted to a small set of types: Boolean, Char, (S)Byte, (U)Int16, (U)Int32, (U)Int64, Single, Double, String, Type and Object.
  2. You can use single dimension arrays of the previous types (though you shouldn’t use them as positional parameters).
  3. Attribute usage in C# force us to use a compile-time constants. In practice, this means that Type “values” are initialized through the typeof operator. Object “values” can be initialized with any value of the list presented in 1 or any other constant expression (you can use null!). Once again, if the expression generates a value type value, it will get boxed at runtime.

These rules are needed due to the work performed by a compiler when it finds an attribute applied to a type or mem
ber. When that happens, the compiler needs emit information into the type’s or member metadata table so that it can create an instance of that attribute at runtime (each parameter is serialized before being stored and that is why we’re limited to those types and we can only resort to constant expressions).

In the next post, we’ll see how we can influence the elements to which attributes are applied. Stay tuned for more.

Advertisements

~ by Luis Abreu on June 18, 2011.

3 Responses to “Getting started with attributes in .NET– part II”

  1. Hi Luis,
    How would you deal with localization in attributes, so you can have a localizable string defined in a resx?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: