Attributes and Reflection in C#
page 1 of 1
Published: 16 Mar 2006
Unedited - Community Contributed
Abstract
Attributes are a mechanism for adding metadata. Reflection is the process by which a program can read its own metadata. This article discusses both these concepts in detail with examples wherever necessary.
by Joydip Kanjilal
Feedback
Average Rating: 
Views (Total / Last 10 Days): 13393/ 10

Attributes provide a powerful way to extend metadata by associating declarative information with C# code. The attribute information is stored with the metadata of the element and can be easily retrieved at runtime using reflection.

Attribute

An attribute is essentially an object that represents the data that is associated with a program element. The element to which an attribute is attached is referred to as the target of that attribute.

Attribute targets can be one of the following:

·         All

·         Assembly

·         Class

·         Constructor

·         Delegate

·         Enum

·         Event

·         Field

·         Interface

·         Method

·         Module

·         Parameter

·         Property

·         ReturnValue

·         Struct

Types of Attributes

Attributes are basically of two types, intrinsic and custom.

Intrinsic Attributes

Intrinsic attributes are supplied as part of the Common Language Runtime, and they are integrated into .NET.

In this example below we use a pre–defined attribute, Obsolete, which marks a program entity as obsolete. The attribute accepts two parameters of which the first is a message and the second a boolean value. If the second parameter is true, the compiler gives an error if the method is invoked, and a warning otherwise.

Listing 1: Using the Obsolete Attribute

using System;
public class Test
{
  [Obsolete("This method is deprecated. Usethe method Display(string) 
  instead."false)]
  void Display()
  {
  }
  void Display(string s)
  {
  }
  public static void Main( ) 
  {
  Test test = new Test ();
  test.Display ();
  }
}

Custom Attributes

Custom attributes are attributes that we create for our own purposes. Attributes are public classes and are initialized using constructors. Every attribute must have at least one constructor. The constructors can be overloaded to allow the attribute to be applied to the class in multiple ways.

To create a custom attribute, we have to derive our new custom Attribute class from the class System.Attribute, as shown below.

Listing 2: Declaring a Custom Attribute Class

using System;
public class Comments : Attribute
{
}

Next, we have to specify the target of the attribute using the AttributeUsage attribute. An attribute is applied to the target by specifying the attribute name in brackets as shown in the example below.

Listing 3: Declaring the Custom Attribute Class

public class Comments : System.Attribute[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
AttributeUsage

The scope and target of the attribute can be defined by applying AttributeUsage. It contains three properties, which we can set to specify attributes.

AllowOn

This is a set of flags that indicates the program entities on which the attribute can be placed. Multiple AttributeTargets can also be specified using a bitwise OR operator.

AllowMultiple

AllowMultiple lets you specify whether you can apply multiple instances of a particular attribute to the same element. If AllowMultiple is set to true, then inherited classes will inherit all instances of the attribute from the parent class. The default value for AllowMultiple is false.

Inherited

The Inherited property determines whether the attribute will be inherited by classes that are derived from the classes to which the attribute is applied. The default value for Inherited is true, indicating that an attribute applied to the base class will be applied to all its derived classes.

Attribute Parameters

Attributes accept parameters for customization. They take two types of parameters, positional and named.

Positional Parameters: Positional parameters are specified using constructor arguments to the attribute class.

Named Parameters: Named parameters are defined by having a non-static field or property in the attribute class.

Attribute parameter types can be:

bool, byte, char, double, float, int, long, short, string

System.object

System.Type

A public enum

A one-dimensional array of the above types

Implementing a Custom Attribute class

The following section shows a custom attribute class called Comments, the application of the attribute to several entities of a class called Employee, and usage of reflection on this class to retrieve the attributes already specified. In the Comments class, the parameters author, type, and description are compulsory positional parameters and status is an optional named parameter.

Listing 4: Implementing the Custom Attribute Class

using System;
using System.Reflection; 
[AttributeUsage( AttributeTargets.All )]
public class Comments : System.Attribute
{
 public string author = String.Empty;
 public string type = String.Empty;
 public string description = String.Empty;
 private string status = String.Empty;
 public Comments(string author, string type,string description)
 {
  this.author = author;
  this.type = type;
  this.description = description;
 }
 public string Status
 {
  get
  {
   return status;
  }
  set
  {
   status = value;
  }
 }
 public static void DisplayAttributes(Type t) 
 {
  Comments comments = (Comments) Attribute.GetCustomAttribute(t,typeof   
  (Comments));
  Console.WriteLine("The Author is:{0}." , comments.author);
  Console.WriteLine("The Description is:{0}." , comments.description);
  System.Console.WriteLine("Class Name:{0}", t.Name); 
  MethodInfo[] methods = t.GetMethods(); 
  object[] attributes = null;
  for (int i = 0, l = methods.GetLength(0); i< l; i++) 
  {
   MethodInfo mi = methods[i];
   attributes = mi.GetCustomAttributes(true);
   foreach (Attribute attribute in attributes) 
   {
    if (attribute is Comments) 
    {
     Comments theComments = (Comments)attribute;
     System.Console.WriteLine("Name: {0} ,Type : {1}, Purpose: {2} , Created 
     By : {3}", mi.Name, theComments.type ,theComments.description, 
     theComments.author );
    } 
   }
  } 
 }
}
 
[Comments("Joydip","Class","Employee Entity")]
class Employee
{
 private string employeeName;
 private int basic;
 [Comments("Joydip","Property","Set/Retrieve name of the employee", Status = 
 "Complete")]
 public string Name
 {
  get 
  {
   return employeeName;
  }
  set
  {
   employeeName = value;
  }
}
 [Comments("Joydip","Property","Set/Retrieve basic salary of the employee",  
 Status = "Complete")]
 public int Basic
 {
  get
  {
   return basic;
  }
  set
  {
   basic = value;
  }
}
 [Comments("Joydip","Method","Display employee details", Status = 
 "Complete")]
 public void Display()
 {
  Console.WriteLine ("The name is"+basic);
  Console.WriteLine ("The basic is"+basic);
 }
 public static void Main(string[] args)
 {
  Employee employee = new Employee ();
  Comments.DisplayAttributes(typeof(Employee));
  System.Console.Read(); 
 } 
}

The method DisplayAttributes displays all the attributes set to the elements of the class Employee using reflection.

Reflection

Reflection provides objects that encapsulate assemblies, modules, and types. It is the process by which a program can inspect metadata information dynamically using the reflection API. Using reflection, we can create instances of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. Reflection is much the same as RTTI of native C++ but with a major difference in that reflection in C# works with managed code and is much more powerful.

The reflection classes are contained in the namespace System.Reflection. The classes in the Reflection namespace, along with the System.Type and System.TypedReference classes, provide support for examining and interacting with the metadata. The abstract base class Type helps access metadata information. The types include the constructors, methods, fields, properties, and events of a class and the module and the assembly in which these are stored.

The System.Reflection namespace defines the following types:

·         Assembly

·         Module

·         Enum

·         MethodInfo

·         ConstructorInfo

·         MemberInfo

·         ParameterInfo

·         Type

·         FieldInfo

·         EventInfo

·         PropertyInfo

 

Here is a complete example of a class that inspects another class and demonstrates the power of reflection to display the metadata information dynamically.

Listing 5: Reflection in Action

using System;
using System.Reflection;
namespace ReflectionTest
{
 public class Employee
 {
  string name;
  public string Name
 {
  get
  {
   return name ; 
  }
  set
  {
   name = value ; 
  }
}
 public Employee()
 {
 }
 public Employee ( string name )
 {
  this.name = name;
 }
 public void Display ()
 {
 }
}
public class Reflect
{
 public static void DisplayDetails(Type type)
 {
  Console.WriteLine ( "Class: " + type) ;
  Console.WriteLine ();
  Console.WriteLine ( "Namespace: " +type.Namespace ) ;
  Console.WriteLine ();
  ConstructorInfo[] constructorInfo = 
  type.GetConstructors( );
  Console.WriteLine( "Constructors:--") ;
  foreach( ConstructorInfo c in constructorInfo)
  {
   Console.WriteLine( c ) ;
  }
 
  PropertyInfo[] propertyInfo =type.GetProperties( );
  Console.WriteLine ();
  Console.WriteLine( "Properties:--" );
  foreach( PropertyInfo p in propertyInfo )
  {
   Console.WriteLine( p ) ;
  }
  MethodInfo[] methodInfo = type.GetMethods( ) ;
  Console.WriteLine ();
  Console.WriteLine( "Methods:--" ) ;
  ParameterInfo[] parameterInfo = null;
  foreach( MethodInfo m in methodInfo )
  {
   Console.WriteLine( "Method Name: "+ m.Name ) ;
   parameterInfo = m.GetParameters () ;
   foreach ( ParameterInfo p in parameterInfo )
   {
    Console.WriteLine("Parameter Type:" + p.ParameterType + " Parameter 
    Name: " + p.Name ) ;
   }
  } 
 }
  public static void Main ( string[] args )
  {
    DisplayDetails(typeof(Employee));
  } 
 }
}

 

Conclusion

C# is an imperative language, but it also offers scope for adding declarative features to the code and their later retrieval if necessary. We can use attributes to provide both design-level and run-time information to our code.

 

For Further Reading

http://www.oreilly.com/catalog/progcsharp/chapter/ch18.html

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vcwlkattributestutorial.asp

http://www.vijaymukhi.com/documents/books/csbasics/chap14.htm

http://www.c-sharpcorner.com/1/CustomAttribute.asp

http://www.ondotnet.com/pub/a/dotnet/excerpt/prog_csharp_ch18/index.html?page=1

 



User Comments

Title: Very Good Article   
Name: Vinayak Bhadage
Date: 2006-09-28 7:54:11 AM
Comment:
This is realy best article to understand attribute and reflction along with example.
Title: Very Good Article For attributes   
Name: Birendra Kumar
Date: 2006-07-19 12:59:15 AM
Comment:
This is very good article for understanding Attributes and reflection. this is gives good sample example also which is easy to understand.
Title: Flash C#   
Name: Steven
Date: 2006-04-01 8:53:42 AM
Comment:
Do you know how to convert .fla to .swf in C#?
thanks
Title: superb   
Name: raja mohamed
Date: 2006-03-23 12:41:37 AM
Comment:
easy to unserstand
Title: Nice Article   
Name: Seema Agarwal
Date: 2006-03-17 10:20:38 AM
Comment:
The article is very good and there are a lot of programs but Sir, you should have written more on Reflection.
Title: Good   
Name: Ravi
Date: 2006-03-17 3:41:48 AM
Comment:
The article is very compact and contains a lot of examples. Very good work. Nice article.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-18 10:28:25 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search