28.5 The AttributeUsage attribute


28.5 The AttributeUsage attribute

It's about time we examined the AttributeUsage attribute in greater detail. After all, AttributeUsage is the special attribute you apply to all your attribute classes so that the C# compiler knows how you want your attribute to work.

A class that is tagged with AttributeUsage must be a subclass of System.Attribute , or else a compilation error will occur. The AttributeUsage attribute specification can take in three parameters “ one positional (and hence mandatory) and two named ones:

  • AttributeTarget “ an int to indicate which types and class entities this attribute class can be applied to (this parameter is mandatory [5] );

    [5] Take it that the AttributeUsageAttribute class itself has only one constructor which takes in an int as a parameter.

  • AllowMultiple “ a boolean public property of the AttributeUsage class (optional; default = false );

  • Inherited “ a boolean public property of the AttributeUsage class (optional; default = false ).

Details of each of these follows .

28.5.1 AttributeTarget parameter

You need to provide a value for this positional parameter. You can use the AttributeTargets enum to pass in an int value to the AttributeTarget parameter.

You can pass in any of the following enum elements:

  • AttributeTargets . All

  • AttributeTargets . Assembly

  • AttributeTargets . Class

  • AttributeTargets . Constructor

  • AttributeTargets . Delegate

  • AttributeTargets . Enum

  • AttributeTargets . Event

  • AttributeTargets . Field

  • AttributeTargets . Interface

  • AttributeTargets . Method

  • AttributeTargets . Module

  • AttributeTargets . Parameter

  • AttributeTargets . Property

  • AttributeTargets . ReturnValue

  • AttributeTargets . Struct

Passing in AttributeTargets.All into this parameter will make this attribute class applicable to all the types and class members listed. Passing in AttributeTargets.Field , for example, will restrict this attribute to tagging fields only. Figure 28.4 shows some examples.

Figure 28.4. Examples of how different attribute classes are used. Each attribute class is given a default constructor since none is coded.

graphics/28fig04.gif

You can use the bitwise OR operator () to create your own combinations:

 [AttributeUsage(AttributeTargets.MethodAttributeTargets.Class)] public class MyMethodAttribute:Attribute{ } 

The code fragment above defines an attribute class that can be applied to either methods or classes.

28.5.2 AllowMultiple parameter

This is an optional named parameter. If AllowMultiple is set to true , this attribute becomes a multi-use attribute. Otherwise, it becomes a single-use attribute. The default value of the AllowMultiple property is false .

The code fragment below creates an attribute class that can be applied to methods only, and which is a multi-use attribute:

 [AttributeUsage(AttributeTargets.Method,  AllowMultiple  =  true  )] public class MyMethodAttribute:Attribute{ } 

Just what are multi-use and single-use attributes? Attributes can be classified as single-use or multi-use. A single-use attribute is one which can be applied only once to a particular type or class entity. For example, if [Author] is a single-use attribute which is to be tagged to methods, the following will cause a compilation error:

  [Author("Mok","21 Dec 02")]   [Author("Mandy","22 Dec 02")]  public void DoSomething(){   // some code } 

A single-use attribute can only be applied once to the same type or class entity. A multi-use attribute, on the other hand, can be applied an unlimited number of times. If [Author] is a multi-use attribute, the above code fragment will work fine and each attribute specification will correspond to a distinct attribute instance of the AuthorAttribute class.

It does not matter which attribute specification appears first. Functionally there is no difference between the code fragment above and this:

  [Author("Mandy","22 Dec 02")]   [Author("Mok","21 Dec 02")]  public void DoSomething(){   // some code } 

Another way to use two [Author] attributes on the same method is this:

  [Author("Mok","21 Dec 02"),Author("Mandy","22 Dec 02")]  public void DoSomething(){   // some code } 

This code fragment is equivalent to the previous one, and creates two distinct instances of the AuthorAttribute class.

28.5.3 Inherited parameter

This is an optional named parameter. If Inherited is set to true , this attribute, when applied to a type or class entity, will be automatically inherited to subtypes and overridden class entities.

The code fragment below creates an attribute class that can be applied to methods only, and which is inheritable:

 3: [AttributeUsage(AttributeTargets.Method,  Inherited  =  true  )]  4: public class MyMethodAttribute:Attribute{  5: } 

MyMethodAttribute is applied to the DoSomething method in the Parent class:

 7: class Parent{  8:  [MyMethod()]  9:   public virtual void DoSomething(){ 10:   } 11: } 12: class Child:Parent{ 13:   public override void DoSomething(){ 14:   } 15: } 

Since MyMethodAttribute is inheritable, the DoSomething() method in the Child class also inherits the attribute implicitly. And here's the proof:

 1: using System;  2: using System.Reflection;  3:  4: [AttributeUsage(AttributeTargets.Method,  Inherited  =  true  )]  5: public class MyMethodAttribute:Attribute{  6: }  7: // --------------------------------------------------  8: class Parent{  9:  [MyMethod()]  10:   public virtual void DoSomething(){ 11:   } 12: } 13: class Child:Parent{ 14:   public override void DoSomething(){ 15:   } 16: } 17: // -------------------------------------------------- 18: class TestClass{ 19: 20:   public static void Main(){ 21: 22:     Type type = typeof(  Child  ); 23: 24:     object []methods = type.GetMethods(); 25:     Attribute methAttr; 26:     Console.WriteLine("These are the marked methods:"); 27: 28:     // print all methods which are marked with MyMethod attribute 29:     foreach(MethodInfo method in methods){ 30:       object []methAttrArr = method.GetCustomAttributes(true); 31: 32:       for (int i=0; i<methAttrArr.Length; i++){ 33:         methAttr = (Attribute) methAttrArr[i]; 34:         if (methAttr is MyMethodAttribute){ 35:           MyMethodAttribute buggy = (MyMethodAttribute)methAttr; 36:           Console.WriteLine(method.Name); 37:         } 38:       } 39:     } // end foreach 40: 41:   } // end Main 42: } 43: 

Output:

 c:\expt>test These are the marked methods: DoSomething 

Note that we are reflecting on the Child class, not the Parent class (line 22). From the output, it would seem as if DoSomething() of Child has had the MyMethodAttribute applied.

Let's change line 4 to:

 4: [AttributeUsage(AttributeTargets.Method,  Inherited  =  false  )] 

The output changes:

 c:\expt>test These are the marked methods: 

No method in Child has been determined as tagged by MyMethodAttribute . Child 's DoSomething() is no longer considered tagged because the attribute is not inherited.



From Java to C#. A Developers Guide
From Java to C#: A Developers Guide
ISBN: 0321136225
EAN: 2147483647
Year: 2003
Pages: 221
Authors: Heng Ngee Mok

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net