Following post describes about the attributes in the .net framework.
MSDN says, Attribute is a method of associating declarative information with code entities (i.e. types, methods, properties, and so forth). Attributes add metadata information to program. There are two types of attributes : Pre Defined Attributes and Custom Attributes
Pre Defined Attributes :
These attributes are defined inside the .net framework e.g. Serializable, Obsolete etc.
[Serializable]
public class MyClass
{
public MyClass()
{
}
[Obsolete("Do not use. Use New Method", true)]
public void OldMethod()
{ }
public void NewMethod()
{ }
}
Custom Attributes :
Custom attribute is a declarative information created by programmer to meet varied needs. Custom Attribute is like any other class but requires following two conditions :
- Custom Attribute class must declare “AttributeUsage” at class level (However, providing “AttributeUsage” attribute at class level is not must while declaring custom attribute)
- Custome Attribute class must derive from System.Attribute or some other attribute ultimately derived from System.Attribute.
Following is the typical example of creating Custom Attribute and its use :
public class MyAttribute : Attribute
{
public MyAttribute() {}
}
[My]
public class MyClass
{
public MyClass() {}
}
Note: it is a convention to use the word Attribute as a suffix in attribute class names. However, when we attach the attribute to a program entity, we are free not to include the Attribute suffix. The compiler first searches the attribute in System.Attribute derived classes. If no class is found, the compiler will add the word Attribute to the specified attribute name and search for it.
AttributeUsage Attribute has three properties namely,
1. AttributeTargets : Through this property, user can define the entities/targets on which custom attribute can be applied. Valid target entities settings are
· Assembly,
· Module,
· Class,
· Struct,
· Enum,
· Constructor,
· Method,
· Property,
· Field,
· Event,
· Interface,
· Parameter,
· Delegate,
Targets can be defined in different combinations for custom attributes e.g.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor)]
public class MyAttribute : Attribute
{
public MyAttribute() {}
}
If user wants to allow custom attributes to be defined on all of above entities, user can use AttributeUsage(AttributeTargets.All)
2. AllowMultiple : This property defines whether this attribute can be defined on the same target multiple time or not. In following example custom attribute has been applied twice at the class level however this is valid as AllowMultiple property has been set to true. If AllowMultiple is false then following piece of code will result in compile time error.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor, AllowMultiple=true)]
public class MyAttribute : Attribute
{
public MyAttribute() {}
}
[My]
[My]
public class MyClass
{
public MyClass() {}
}
3. Inherited : This property defines whether the attributes applied to targets will get inherited to derived class or not.
If AttributeUsage attribute is not applied while creating custom attribute then it will use default values. Following is the table describing these default values :
|
Parameter
|
Description
|
Default
|
|
AttributeTargets
|
What element of the class the attribute is targetting
|
AttributeTargets.All
|
|
IsAttributeMultiUse
|
Can the attribute be set multiple times.
|
false
|
|
IsAttributeInherited
|
The attribute can be inherited from derived classes.
|
false
|
Let’s consider the combination of these properties in order to understand this better.
|
Attribute
Targets
|
Allow
Multiple
|
Inherited
|
Code
|
Default
|
|
All
|
false
|
False
|
[My(“Base”)]
public class MyBase
{}
Public class MyDerived : MyBase {}
|
No attribute on MyDerived class
|
|
All
|
true
|
false
|
Still no attribute on MyDerived class as Inherited property is still false
|
|
All
|
false
|
true
|
[My(“Base”]
public class MyBase
{}
[My(“Derived”]
Public class MyDerived : MyBase {}
|
Although Inherited property is true but AllowMultiple is false, only attribute with “Derived” information will be applied to derived class
|
|
All
|
true
|
true
|
Attribute with both “Base” and “Derived” information will be applied to MyDerieved class
|
Positional vs. Named Parameters
Positional parameters are parameters of the constructor of the attribute. They are mandatory and a value must be passed every time the attribute is placed on any program entity. On the other hand Named parameters are actually optional and are not parameters of the attribute’s constructor.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor, AllowMultiple=true)]
public class MyAttribute : Attribute
{
protected string name;
protected string info;
public MyAttribute(string attName)
{
name = attName;
}
public string Name
{
get { return name; }
}
public string Info
{
get { return info; }
set { info = value; }
}
}
[My("Tau")]
public class MyClass
{
public MyClass() {}
}
[My("Tau", Info = "This is additional Information")]
public class AnotherClass
{
public AnotherClass() { }
}
In the above example, “Name” is positional parameter while “Info” is named parameter.
It is desriable to use Named parameters in attributes rather than using overloaded constructors in attribute definition.
Now, enough said about how to define attribute. Another important aspect is to how to access this declarative information. As mentioned in the beginning of the article, attribute values can be retrieved using Reflection. .Net framework provide “Attribute.GetCustomAttributes” method which returns the collection of attributes defined on given type. Overloads are available to retrieve the attributes applied to specific targets i.e. methods, constructor, etc. Following code snippet shows how to retrive the value of attribute properties.
Attribute[] attrs = System.Attribute.GetCustomAttributes(t); // reflection
foreach (Attribute attr in attrs)
{
if (attr is MyAttribute)
{
MyAttribute a = (MyAttribute)attr;
System.Console.WriteLine(“Name is {0}, Info is {1}”, a.Name, a.Info);
}
}
Few minds may have a question like the same functionality can be implemented by implementing the property in a class then why to use attribute? Following is the justification of using Attributes :
1. Attributes can be defined at different target levels i.e. methods, constructors, assembly etc. While properties can only be declared at class level.
2. Also, attribute is declarative information. So this information is assigned at the time of compilation and assigned value is not changed normally at runtime. While property value can be changed at runtime.
Recent Comments