Common Type System—Custom Attributes


Jump to: navigation, search
Visual C# Tutorials
.NET Framework Tutorials

Common Type System

© 2006 Wiley Publishing Inc.

Custom Attributes

We’ve seen throughout this chapter various IL keywords that compilers use to modify runtime behavior for the type or member they have been applied to. These are pseudo-custom attributes, which are serialized using a fixed size and location in the metadata and usually have their own efficient storage slots in CLR data structures. The CLR intimately knows about these attributes, will notice them, and will respond to them accordingly, based on the documented contract for the specific attribute.

However, the CLR also permits users to attach custom attributes to CLR data types. This is done by creating a new type that derives from System.Attribute, and providing a set of fields and properties the attribute will carry around when instantiated at runtime. A user of your attribute may then attach an instance to an assembly, module, type, or member. The attribute and its instantiation information are serialized into the assembly’s metadata and can be rehydrated at runtime. User components may then inspect instances at runtime for the presence of these attributes and react accordingly, much like the runtime does with pseudo-custom attributes.

Here is an example attribute type in C#:

[AttributeUsage(AttributeTargets.Class | 
   AttributeTargets.Method)]
class MyAttribute : System.Attribute
{
   private string myString;
   private int mySize;
 
   public MyAttribute(string myName)
   {
      this.myName = myName;
      this.mySize = 8; // default
   }
 
   public string MyName { get { /*...*/ } }
   public int MySize { get { /*...*/ } set { /*...*/ } }
}

A user may then attach this to a class or method (the two legal targets based on AttributeUsage, which itself is an attribute). This is done in C# with the [ Attribute ] syntax and VB with the < Attribute > syntax, for example:

[MyAttribute("MyFoo")]
class Foo
{
   [MyAttribute("MyFoo::MyBar", MySize = 16)]
   public void Bar()
   {
   }
}

Notice that C#’s attribute syntax permits you to call the constructor and supply a set of property values. The System.Reflection.MemberInfo type and all of its derived types (Type, MethodInfo, PropertyInfo, FieldInfo, and so forth) then enable components to read a type system component’s attributes using the GetCustomAttributes method. This small snippet of code reads Foo and Foo.Bar’s attributes:

Type fooType = typeof(Foo);
object[] myAttrOnType = fooType.GetCustomAttributes(
   typeof(MyAttribute), false);
if (myAttrOnType.Length > 0)
{
   // Do something special...it has a MyAttribute.
}
 
MethodInfo fooBarMethod = fooType.GetMethod("Bar");
foreach (object attr in 
   fooBarMethod.GetCustomAttributes(false))
{
   if (attr.GetType() == typeof(MyAttribute))
   {
      // Has a MyAttribute, do something about it.
   }
}

This was a very quick overview. Please refer to Chapter 14, which discusses more about these APIs, the internals of custom attributes, such as their storage format, and more about how they relate to dynamic programming.


Previous_Page_.gif Next_Page_.gif





Personal tools