Using a custom attribute involves writing an attribute class first. Let's examine an example of a custom attribute class called AuthorAttribute : [1]
1: // AttributeClass.cs 2: using System; 3: 4: [AttributeUsage(AttributeTargets.Method)] 5: public class AuthorAttribute:Attribute{ 6: 7: public string AuthorName; 8: public string LastEditDate; 9: 10: // constructor 11: public AuthorAttribute(string authorName, String lastEditDate){ 12: this.AuthorName = authorName; 13: this.LastEditDate = lastEditDate; 14: } 15: } The first thing to realize is that an attribute class must be a direct or indirect subclass of System.Attribute (line 5). Interestingly, you might notice that the class itself is tagged with an [AttributeUsage] attribute specification. [AttributeUsage] is a special standard attribute recognized by the C# compiler. It is used to provide more information about the attribute class you are writing. [AttributeUsage(AttributeTargets. Method )] on line 4 means that this AuthorAttribute attribute can only be used on methods . Tagging a class, event, delegate, or any other class entity with [AuthorAttribute] will cause a compilation error. If you want your attribute to be used for any class entity, replace line 4 with: [AttributeUsage(AttributeTargets. All )] Lines 11 “ 14 define the constructor for AuthorAttribute . The constructor takes in two strings “ the author's name , and the last edited date (as a string). This is the way the attribute is to be used in MyClass.cs (section 27.1): [AuthorAttribute("Name", "23 Dec 02")] What the attribute specification above actually does is create an instance of the AuthorAttribute class and pass in the strings "Name" and "23 Dec 02" into the constructor, which in turn initializes fields AuthorName and LastEditDate to these values passed in. You can write other overloaded constructors for your attribute class, as long as the attribute specification matches any one of them. Since custom attributes are only useful if you want to retrieve their values during runtime via C#'s reflection API, here is another class which does just that. 1: // Test.cs 2: using System; 3: using System.Reflection; 4: 5: class TestClass{ 6: public static void Main(){ 7: 8: Type type = typeof(MyClass); 9: object []methods = type.GetMethods(); 10: 11: foreach(MethodInfo method in methods){ 12: object []attributes = method.GetCustomAttributes(true); 13: 14: Attribute attr; 15: 16: for (int i=0; i<attributes.Length; i++){ 17: attr = (Attribute)attributes[i]; 18: if (attr is AuthorAttribute){ 19: AuthorAttribute author = (AuthorAttribute)attr; 20: Console.Write("method name: " + method.Name); 21: Console.WriteLine 22: (", Written by: " + author.AuthorName); 23: } 24: } 25: 26: } // end foreach 27: } // end Main 28: } You should be able to work out what is happening in Main() since the reflection method names are quite intuitive. See Chapter 16 for more information on reflection. When TestClass executes, line 8 will assign the Type of the MyClass class to local variable type . Line 9 uses reflection to obtain the methods (encapsulated as an array of MethodInfo object) of the MyClass type dynamically. For each MethodInfo object, the custom attributes applied to the method are obtained (again through reflection) (on line 12) into an array of Attribute objects. Each method may be associated with more than one attribute. If the method's attribute matches AuthorAttribute , a cast is performed (line 19), and the method's name together with the corresponding Author attribute's AuthorName field are printed out (lines 20 “ 22). We need to compile all three classes ( Test.cs , AttributeClass.cs , and MyClass.cs in section 27.1). If you are using csc.exe and have coded the classes in three separate source files, this is the way to do it: c:\expt>csc AttributeClass.cs MyClass.cs Test.cs This command will produce a single Test.exe assembly containing all the codes in the three files. [2]
Here is the output when Test.exe is executed: c:\expt>test method name: DoSomething, Written by: Mok method name: DoSomethingElse, Written by: Mindy method name: DoNothing, Written by: Abigail You have dynamically searched for methods tagged with the Author attribute in a .NET assembly, and retrieved the value stored in the public field AuthorName of each Author attribute instance. All this is done during runtime via reflection. |