Attributes in C#

Attributes are a new kind of declarative information. We can use attributes to define both design-level information (such as help file, URL for documentation) and run-time information (such as associating XML field with class field).
We can also create “self-describing” components using attributes. In this tutorial we will see how we can create and attach attributes to various program entities, and how we can retrieve attribute information in a run-time environment.
As stated in MSDN
“An attribute is a piece of additional declarative information that is specified for a declaration.”
What is an attributes?
An attribute is information which marks the elements of code such as a class or method.
For example: .NET framework provides the system.obsoleteAttribute attribute which can be used to mark a method as follows [we use [] brackets to attach attributes to code elements]:
[System.ObsoleteAttribute ()]
void Fool{}
The Fool method is marked with the system.ObsoleteAttribute. Attribute information is inserted in the assembly during the time of compilation. This information then can be used by the c# compiler. When it encounters a call to method, it can then produce a warning, indicating that it’s better to avoid call to an obsolete method, which risks of going away in future versions.
Without an attribute, you would be forced to properly document the fact that Fool() method is now obsolete the weakness of this approach is that you will have no guarantee that your clients will read the documentation and be aware of the fact that method is now obsolete.
When do we need attributes?
The advantage of using attributes resides in the fact that the information that it contains is inserted into the assembly. This information can then be consumed at various times for all sorts of purposes:
1. An attribute can be consumed by the compiler such attributes are also named pseudo-attributes. The System.ObsoleteAttribute attribute that we have just described is a good example of how an attribute is used by the compiler; certain standard attributes which are only destined for the compiler are not stored in the assembly.
For example, the SerializationAttribute attribute does not directly mark a type but rather tells the compiler that type can be serialized. Consequently, the compiler sets certain flags on the concerned type which will be consumed by the CLR during execution such attributes are also named pseudo-attributes.
2. An attribute can be consumed by the CLR during execution. For example the .NET Framework offers the System.ThreadStaticAttribute attribute. When a static field is marked with this attribute the CLR makes sure that during the execution, there is only one version of this field per thread.
3. An attribute can be consumed by a debugger during execution. Hence, the System.Diagnostics.DebuggerDisplayAttribute attribute allows personalizing the display of an element of the code(the state of an object for example) during debugging.
4. An attribute can be consumed by a tool, for example, the .NET framework offers the System.Runtime.InteropServices.ComVisibleAttribute attribute. When a class is marked with this attribute, the tlbexp.exe tool generates a file which will allow this class to be consumed as if it was a COM object.
5. An attribute can be consumed by your own code during execution by using the reflection mechanism to access the information. For example, it can be interesting to use such attributes to validate the value of fields in your classes.
Such a field must be within a certain range. Another reference field must not be null. A string field can be at most 100 characters. Because of the reflection mechanism, it is easy to write code to validate the state of any marked fields. A little later, we will show you such an example where you can consume attributes by your own code.
6. An attribute can be consumed by a user which analyses an assembly with a tool such as ildasm.exe or Reflector. Hence you could imagine an attribute which would associate a character string to an element of your code. This string being contained in the assembly, it is then possible to consult these comments without needing to access source code.
Things to know about attributes
1. An attribute must be defined by a class which derives from System.Attribute. An Instance of the attribute class is only instantiated when the reflection mechanism accesses one of its representatives, Depending on its use, an attribute class in not necessarily instantiated (as with the System.ObsoleteAttribute class which does not need to be used by the reflection mechanism).
2. The .NET framework puts several attributes to your disposition. Certain attributes are destined to be used by the CLR. Other are consumed by the compiler or tools supplied by Microsoft.
3. You have the opportunity of creating your own attribute classes, they will then necessarily be consumed by your program as you cannot tinker the compiler or the CLR.
4. By convention, the name of an attribute class is suffixed by Attribute. However, an attribute named XXXAttribute can be used in c# both using the XXXAttribute expression but also with the XXX expression when it marks an element of the code.
How to use attributes
Simple Attributes
In C# attributes are placed before the item that they will be “decorating” and they are put inside square braces [].
public class MySerializableClass
Like C#, VB.NET places attributes before the item that will be decorated, except VB.NET uses angle brackets <>.
Public Class MySerializableClass ….
Notice that even though the real name for the attribute is SerializableAttribute we didn’t write Attribute? The only time that you can leave off the Attribute portion of the name is when you are applying the Attribute to a class.
The code above actually expands out to
public class MySerializableClass
This shortened name can only be used when the attribute is being applied in your code that uses the attribute you must use the full name.
SerializableAttribute [] sa = (SerializableAttribute []) type.GetCustomAttributes(typeof(SerializableAttribute), false);
Note: Here I had to give the full name just as I would with any other class.
More complex attributes
The constructor for MarshalAs is defined as
public MarshalAsAttribute(UnmanagedType);
Note that it only accepts one parameter, what about the other properties?

Remember that this is the most confusing part about attributes.

This is the most confusing part about attributes so you may have to do a couple examples before this part clicks since it deviates from normal C style methods and gets into a VB-esque style.
You set the properties in the constructor, after all the parameters for the constructor. For example, we’re going to pass an array of three 32-bit integers to a method, I’ll skip the actual void MyMethod garbage since you can see that above
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.I4)]
I don’t want to consider that you down with the specifics of MarshalAs since I just want to use it as an example, but you can see that the first thing passed in was a member of the UnmanagedType enum, followed by setting of two properties SizeConst and ArraySubType.
Note: VB programmers will remember this as passing by name.
AttributeUsage Attribute
Another part of the attribute definition is the AttributeUsage statement that apperars just above the actual class definition. This statement is a modifier to the class declaration itself. By adding an AttributeUsage statement, we declare to the compiler that this class can and will be used as an attribute to other classes.
The AttributeUsage statement defines how the attribute can be used in the system. The argument to the AttributeUsage statement is an AttributeTargets element. If you do not specify for which target you want to allow the attribute to be used, the default is used for all of them. The given table shows the available target and how these attributes are used in the sample code.
Attribute targets and their application
Attribute Targets How it is applied
All Any element
Assembly Any assembly
Class Any Class
ClassMembers A class, a structure, an enumeration, a constructor, a destructor, a method, a property, a field, an event, a delegate, or an interface
Constructor Only class constructor
Delegate Any delegate
Enum Any enumeration
Field Any field in a class
Interface Any interface for class derivation
Method Any method within a class
Module Any module level entity
Parameter One or more parameters to a method
Property Any property of a class
Return Value Any return value of a method
Struct A structure
Note: Multiple types can be combined for any given
To Download Attributes example Click here.
To view downloaded examples, Please Ensure that .NET Framework is installed on your system.
Scroll to Top