Overview Of C# Attributes

In the article, we will look at C# attributes and their usage. Attributes have been in C# for quite some time, and are used for adding metadata in programming elements like assemblies, types, classes, methods, and properties. During compilation, this metadata converts to IL then adds to PE file and can be retrieved using reflection. We can use pre-defined attributes like Obsolete by importing the corresponding namespace (or) by writing custom attributes that can also be defined. We will create custom attributes and retrieve the  same using Reflection in sample application.

Let’s create a sample console application in VS 2015. Then, add a class MyAttribute.cs with below code, 

  1. namespace AttributesDemo {  
  2.       
  3.     [AttributeUsage(AttributeTargets.Class, Inherited = false)]  
  4.     public class ClassAttribute: Attribute {  
  5.         public string Name { get; set; }  
  6.         public int Number { get; set; }  
  7.     }  
  8.     [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor ,AllowMultiple=true)]  
  9.     public class MethodOrConstructor : Attribute  
  10.     {  
  11.         public string Name { get; set; }  
  12.     }  
  13.     [AttributeUsage(AttributeTargets.All)]  
  14.    public class MyAttribute: Attribute  
  15.     {  
  16.           
  17.     }  
  18. }   

A custom attribute declaration starts with AttributeUsage with below optional members:

AttributeTargets

This is used to specify to which all program elements, we can apply this attribute. For example, setting it as AttributeTargets.Class will allow to apply it on class construct only. Similarly, we can restrict it to a interface, method or constructor etc.

Inherited

This is used to specify whether your attribute can be inherited by classes that are derived from the classes to which your attribute is applied and default is true.

AllowMultiple

This is used to specify whether multiple instances of your attribute can exist on an element and default is false.

It is mandatory to declare attribute classes as public ones, which ones should inherit from System.Attribute and a good practice to end class name with Attribute for better readability.

Let’s decorate our constructs with the above attributes and use reflection to query their existence and values,

  1.  namespace AttributesDemo {  
  2.     class Program  
  3.     {  
  4.         static void Main(string[] args)  
  5.         {  
  6.             #region Main  
  7.   
  8.             var attributes = Attribute.GetCustomAttributes(typeof(MyClass), typeof(ClassAttribute));  
  9.             if (attributes.Any())  
  10.             {  
  11.                 foreach (var attribute in attributes)  
  12.                 {  
  13.                     Console.WriteLine("Attribute Value: " + ((ClassAttribute) attribute).Name);  
  14.                     Console.WriteLine("Attribute Value: " + ((ClassAttribute) attribute).Number);  
  15.                     Console.WriteLine("Type ID: " + attribute.TypeId);  
  16.                 }  
  17.             }  
  18.             MemberInfo classInfo = typeof(MyClass);  
  19.             foreach (object attrib in classInfo.GetCustomAttributes(true))  
  20.             {  
  21.                 Console.WriteLine("Attribute Value: " + ((ClassAttribute) attrib).Name);  
  22.                 Console.WriteLine("Attribute Value: " + ((ClassAttribute) attrib).Number);  
  23.             }  
  24.             Console.ReadLine();  
  25.             #endregion  
  26.         }  
  27.     }  
  28.   
  29.     [Class(Name = "Test")]  
  30.     class MyClass  
  31.     {  
  32.         [MethodOrConstructor]  
  33.         [MethodOrConstructor]  
  34.         MyClass()  
  35.         {  
  36.         }  
  37.   
  38.         [MethodOrConstructor, MethodOrConstructor]  
  39.         public int GetId()  
  40.         {  
  41.             return 10;  
  42.         }  
  43.         [My]  
  44.         public string Name { get; set; }  
  45.     }  
  46. }   

Here, we decorated MyClass with Class attribute, MethodOrConstructor attribute on a method, constructor and My attribute on a property. We can use either MemberInfo.GetCustomAttributes and Attribute.GetCustomAttributes for retrieving multiple instances of an attribute applied to the same scope. We can use getCustomAttribute to retrieve a single instance of an attribute. 

  1. class Program  
  2.     {  
  3.         static void Main(string[] args)  
  4.         {  
  5.             #region Main  
  6.   
  7.             var attributes = Attribute.GetCustomAttributes(typeof(MyClass), typeof(ClassAttribute));  
  8.             if (attributes.Any())  
  9.             {  
  10.                 foreach (var attribute in attributes)  
  11.                 {  
  12.                     Console.WriteLine("Attribute Value: " + ((ClassAttribute) attribute).Name);  
  13.                     Console.WriteLine("Attribute Value: " + ((ClassAttribute) attribute).Number);  
  14.                     Console.WriteLine("Type ID: " + attribute.TypeId);  
  15.                 }  
  16.             }  
  17.             MemberInfo classInfo = typeof(MyClass);  
  18.             foreach (object attrib in classInfo.GetCustomAttributes(true))  
  19.             {  
  20.                 Console.WriteLine("Attribute Value: " + ((ClassAttribute) attrib).Name);  
  21.                 Console.WriteLine("Attribute Value: " + ((ClassAttribute) attrib).Number);  
  22.             }  
  23.             Console.ReadLine();  
  24.             #endregion  
  25.         }  
  26.     }   

Output


By using attributes, we can add additional descriptive details that modify types and members.

I am ending things here. I hope this was informative.