|Custom Attributes In C#|
|Written by Mike James|
|Tuesday, 23 June 2015|
Page 2 of 4
The Attribute Constructor
So far so good but currently the instance of the attribute’s class isn’t doing us a lot of good as the class has no methods and, more importantly, no properties.
There are two ways of providing it with properties. The first is to provide a constructor with parameters.
For example, if we change the ASCII class definition to:
we can pass some data to the class by applying the attribute as:
Now when the GetCustomAttributes method is called it returns a single instance of the ASCII class with MyData set to “Hello Attribute World”.
In other words, calling the GetCustomAttributes method has resulted in the class constructor being used with the data provided by the ASCII attribute tag.
The tag is a call to the constructor and you can think of:
as being equivalent to:
being executed when you call GetCustomAttributes on any class that the attribute is applied to so returning an instance complete with what ever initialisation the constructor has performed.
To see that you have indeed got an instance of the ASCII class complete with the string set by the constructor try:
After casting the returned array to ASCII you can access all its public methods and properties. While this isn’t the way that attributes are normally used it is perfectly valid.
As well as using the constructor to initialise the instance, you can also use named parameters to initialise member variables. For example, if we add a public variable MoreData to the attribute class:
it can be initialised using:
Now when GetCustomAttributes is called the instance is constructed as follows:
Once again you can test this assertion by using a MessageBox:
where you will discover that the public string MoreData has indeed been set to “SomeData” by the attribute.
You should now be able to see the general principle:.
Notice that all of the unnamed parameters have to come before the named parameters. So for example, an attribute applied as:
when the GetCustomAttributes method is used.
Notice also that named parameters are optional, if they are not supplied then the corresponding variable is left uninitialised.
It is also important to know that the type of parameter you can use is limited to the majority of the simple types, i.e. int, long, float, string, System.Type, object, a publicly accessible enum and a one-dimensional array of any allowable type.
You might think that as you can pass an object you can pass anything but this isn’t the case. There is an additional condition that restricts parameters to constants of the appropriate type.
So you can have:
but you can’t have:
or anything like it.
Each time you request the details of an attribute a new object is instantiated no matter what class is involved.
So for example, if we go back to the simpler version of ASCII with a single parameter constructor, the following:
does indeed create distinct attribute instances as you can demonstrate:
The result is two messageboxes that correctly show each of the messages set by the attribute tags.
However you get two instances even if you call GetCustomAttributes a second time on the same class.
What isn’t generally realised is that you can change attribute values fairly easily at runtime. The reason is, of course, that the instances of the attribute classes that are created are perfectly normal objects and can be used without restriction.
For example, we can get the object:
change the value of its public variable and show that it has changed:
and finally create another instance and show that its value is unchanged:
|Last Updated ( Tuesday, 23 June 2015 )|