Thursday, 5 November 2015

.Net Attributes

I've never been too keen of .Net attributes, I guess because I've always had rather present its big limitation, they are a static, compile time feature, you can not add, delete or modify an attribute for a class, method or property at run time. In part as a consequence of this, they apply at the Type level, not at the instance level, so if you declare a class as [Serializable], all its instances will be Serializable, and you won't be allowed to remove this Serializable attribute.

I think it's common to talk about Attributes just in terms of metadata (notice that when they are applied to classes they are the perfect replacement for the Marker Interfaces. Attributes are more than metadata though, as they have methods they can have behaviour.

Of course Attributes are still pretty useful, but you have to be careful to use them only in situations when these metadata or behaviour are not going to change at runtime, if not, you'll have to keep this information in normal objects that you initialize based on configuration values and that you can change normally later on.

The behaviour for the Java counterpart, annotations, is basically the same as far as I know. On the other side, JavaScript does not have "official" support for Attributes/Annotations (you'll see some libraries that implement them based on comments). But indeed, JavaScript supports dynamic attributes for "classes" and "methods" (I'm talking about pre ES6, that's why I use the quotes). In the end "classes", "methods" and normal functions just come down to functions, functions are objects, and objects can just be expanded with new properties whenever you want. So you can designate your "class" as serializable, or your method/function as "cacheable" just like this:

function Person(){
...
}
Person.serializable = true;

var p1 = new Person();
if (p1.serializable){

}

function algorithm1(){
}

function algorithm2(){
}

algorithm1.fast = false;
algorithm2.fast = true;

if (timeConstrains == true){
algorithm2();
}
else{
algorithm1();
}

Back to .Net attributes, I had never thought about how attributes are stored. I mean, yes an Attribute is a class, but what I wonder is how is stored that one class, method or property is decorated by certain attribute having certain parameters? Everything is stored in the Assembly metadata. You can read here a pretty good explanation.

Going for precision here, all the [attributes] used in an assembly are gathered together by the compiler and written to the metadata of the assembly. Two tables in the metadata play are role.

The first one is the CustomAttribute table, it contains a list of every single attribute. The list entry has an index to the original declaration that had the attribute (1), a reference to the constructor for the attribute type (2) and an index for the value that's used to construct the attribute object at runtime (3).

The second one is the Blob table, the value index (3) in the CustomAttribute table indexes it. It contains the values you used in the attribute declaration. Those values are a string if you used a string or typeof argument, the actual value if you used a value type value argument, an array of those values if you use an array.

Constructing the attribute object at runtime thus involves first finding the entry in the CustomAttribute array by (1). Then locating the constructor for the attribute class by using (2) and jit compiling it if necessary. (3) is used to lookup the entry in the blob table, converting the values in the blob as necessary, like retrieving the Type from the string, creating the array, etcetera. And calling the constructor to create the object.

Organizing it that way has the big advantage that a declaration can have an arbitrary number of attributes and that attributes can be used on many kinds of declarations (assembly, type, method, parameter, field, etc). The disadvantage is that finding them back isn't particularly cheap

Now that we know how they are stored, the next question is, when are attributes created? (I mean, the instances of an Attribute class)
I've been doing some tests, and it goes like this:

  • Creating a class decorated with attributes (the class or its methods or properties) does not create an instance of the attribute.

  • Checking if a class is decorated by an attribute, let's say:
    typeof(Class1).IsDefined(typeof(SimpleAttribute), false);
    does not create an attribute either.

  • Attributes are created for example when code like this is run:
    var attrib2 = typeof(Class1).GetCustomAttributes(typeof(SimpleAttribute), true).FirstOrDefault() as SimpleAttribute;

    You'll use code like that if you need to check some property of an attribute or invoke some of its methods. Think for example in the AuthorizationAttribute and how the framework invokes its Authorize method.

No comments:

Post a Comment