Creating And Using Custom Attributes In C#

Tools Used

Visual C# .NET

What are Attributes?

Here is a quote about what an attribute is all about:

"Attributes provide a powerful method of associating declarative information with C# code (types, methods, properties, and so forth). Once associated with a program entity, the attribute can be queried at run time and used in any number of ways." - MSDN

Attributes are classes that allow you to add additional information to elements of your class structure.

The information from the attribute can later be obtained by using Reflection. See the article on reflection on this site. In this article, we will show you how to add stereotypes to your method. A stereotype is a way to describe a specific category for a design element and is a term that comes from UML. Our stereotype attribute provides two strings to describe our methods, a stereotype string and a description string.
 
Below is the code for declaring our custom attribute, stereotype,
  1. using System;  
  2. using System.Reflection;  
  3. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor)]  
  4. publicclass Stereotype: System.Attribute {  
  5.     publicstring TheStereotypeName = "General";  
  6.     publicstring TheDescription = "Method Info";  
  7.     public Stereotype() {}  
  8.     public Stereotype(string aStereotype, string aDescription) {  
  9.         TheStereotypeName = aStereotype;  
  10.         Description = aDescription;  
  11.     }  
Every class requires two things to make it an attribute.
  1. An AttributeUsage Attribute to declare the class as an attribute.
  2. Derive from System.Attribute or some other attribute ultimately derived from System.Attribute.

    Below is the attribute usage from our example allowing our attribute to be associated with a class or a method or a constructor of a class,

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor)] 
This element before the class takes 3 possible parameters.
Parameter Description Default Example
AttributeTargetsWhat element of the class the attribute is targettingAttributeTargets.Allthe sample attribute targets classes constructors, and methods (see above)
IsAttributeMultiUseCan the attribute be set multiple times.false[Conditional("A"),Conditional("B")]
IsAttributeInheritedThe attribute can be inherited from derived classes.false 

To use our attribute, we simply place it above a method, and call the attribute's constructor. Below is an example of the Stereotype Attribute being used in a class called Customer with methods GetName and SetName. For simplicity, only the methods are displayed below,

  1. // method 1 of our Customer class   
  2. [Stereotype("Accessor""Retrieve the name of the customer")]  
  3. publicstring GetName() {  
  4.     return Name;  
  5. }  
  6. // Method 2 of our customer class  
  7. [Stereotype("Modifier""Set the name of the customer")]  
  8. publicvoid SetName(string aName) {  
  9.     Name = aName;  
Now we'll add a method to our stereotype attribute class that will allow us to retrieve the attribute information from the customer class and write it to the console. The method uses reflection and calls GetCustomAttributes on each item in our methodinfo collection to get a hold of the stereotype attributes of our class,
  1. publicstaticvoid WriteEachMethodInClass(Type t) // method of the Stereotype class  
  2. {  
  3.     System.Console.WriteLine("Methods for Class {0}", t.Name); // write class name to console  
  4.     MethodInfo[] TheMethods = t.GetMethods(); // Get all the methods from the class using reflection  
  5.     for (int i = 0; i < TheMethods.GetLength(0); i++) // cycle through each method and see if it has an attribute  
  6.     {  
  7.         MethodInfo mi = TheMethods[i];  
  8.         object[] attrs = mi.GetCustomAttributes(); // Get collection of custom attributes from the method  
  9.         foreach(Attribute attr in attrs) // get each attribute using foreach  
  10.         {  
  11.             if (attr is Stereotype) // is the attribute a Stereotype Attribute?  
  12.             {  
  13.                 Stereotype theStereotype = (Stereotype) attr; // it is, write the Stereotype and the Description to the console  
  14.                 System.Console.WriteLine("{0} - {1}, {2}", mi.Name, theStereotype.TheStereotype, theStereotype.Description);  
  15.             }  
  16.         }  
  17.     }  
  18.     ConstructorInfo[] TheConstructors = t.GetConstructors(); // do the same for the constructors of our class  
  19.     for (int i = 0; i < TheConstructors.GetLength(0); i++) {  
  20.         ConstructorInfo mi = TheConstructors[i];  
  21.         object[] attrs = mi.GetCustomAttributes();  
  22.         foreach(Attribute attr in attrs) {  
  23.             if (attr is Stereotype) {  
  24.                 Stereotype theStereotype = (Stereotype) attr;  
  25.                 System.Console.WriteLine("{0} - {1},{2}", mi.Name, theStereotype.TheStereotype, theStereotype.Description);  
  26.             }  
  27.         }  
  28.     }  
Here is an example of how we call our WriteEachMethodInClass to write out the stereotype attributes,
  1. publicstaticint Main(string[] args) {  
  2.     Stereotype.WriteEachMethodInClass(typeof(Account)); // Write the stereotype information of Account to the console.  
  3.     Stereotype.WriteEachMethodInClass(typeof(Customer)); // Write the stereotype information of Customer to the console.  
  4.     System.Console.WriteLine("Hit ENTER to continue...");  
  5.     System.Console.Read();  
  6.     return 0;  
  7. }  
Attributes can be used from everything to detailed code documentation, to version control. Look for future articles on this subject coming to C-Sharp Corner.