Metadata Tools and Extensions


A Tool for Reading Metadata

At this point, you are probably thinking that a generic tool for reading and displaying metadata would be a simple and easy application to write and very useful when working with CLR types. In fact, writing such a tool is great first application for familiarizing yourself with the CLR and its concepts. The SDK also supplies such a tool, called the Intermediate Language Disassembler (ILDASM); a tutorial for using ILDASM appears in the SDK as well. Although this book generally avoids using tools that hide the facilities of the CLR, ILDASM is such a wonderful aid when you are starting with the CLR that you are strongly advised to examine types with it. Invoking ILDASM on mscorlib and selecting the Object class would display the information shown in Figure 3.2.

Figure 3.2. Invoking ILDASM on mscorlib and selecting the Object class

graphics/03fig02.gif

Metadata Extensibility

A number of extensions to IDLs provide more semantic information about the interfaces they describe. Some extensions have involved expansion of IDLs and specific IDL compilers with new keywords. This tactic adds the extra semantic information but effectively reduces the extensions to a proprietary language, making sharing of the IDL files produced in this way difficult. Other extensions have added structured comments to IDL files; these comments are ignored by standard IDL compilers but " processed " by extended compilers. Still other extensions have added specific objects or interfaces that describe or provide access to semantic information. Each approach offers certain advantages, and all of them highlight the need to add semantic information.

Custom Attributes

The CLR's metadata facility is extensible via custom attributes . Custom attributes provide a simple and easy means for developers to annotate a type or its members . A custom attribute is essentially a class; an instance of an attribute class is attached to a type or its members and persisted in the metadata for that type. The .NET Framework makes extensive use of custom attributes, as you will see in examples later in this chapter.

Custom attributes share some similarities with the IDL extensions described previously:

  • As with structured comments, the addition of an attribute does not make the type unusable from a compiler that does not understand the attribute. In general, compilers that do not understand the custom attribute will ignore it. Naturally, this characteristic is both an advantage and a disadvantage ; if the compiler does not understand the attribute, then the semantic information it conveys may be lost.

  • Because attributes are classes, it is possible to access instances of these classes at runtime to retrieve information. This ability is similar to that offered by IDL extensions that use interfaces to generate information that can be retrieved at runtime. One limitation of custom attributes is the fact that they do not generate code that is automatically called by the CLR at runtime.

For example, it would be useful if you could use custom attributes to indicate that a parameter of an integral type should contain a value between two user -specified limits. Although you can use an attribute to do so, you cannot instruct the runtime environment to automatically test for this condition. Instead, programs must look for custom attributes and process them as they see fit. Currently, a number of researchers are looking at ways of using custom attributes to provide facilities such as preconditions and postconditions.

While custom attributes classes are not required to inherit from the class System.Attribute , it is recommended that they do so. CLS-compliant custom attributes must inherit from this type. As System.Attribute does not have to be the base class for all attributes, methods such as GetCustomAttributes return arrays of Object s rather than arrays of Attribute s.

Listing 3.4 demonstrates the definition and use of custom attributes. The user-defined attribute stores the name of the author of the type or member to which it is attached. After the initial using directives, we see the use of an attribute, AttributeUsage . It describes the user-defined attribute class that follows . AttributeUsage states that the following attribute class can be applied to all possible targets, including types and members; that multiple instances of this attribute can be applied to a target; and that subtypes and methods inherit these custom attributes.

Listing 3.4 Using custom attributes
 using System; using System.Reflection; [AttributeUsage(AttributeTargets.All,    AllowMultiple = true,    Inherited = true)] public class AuthorAttribute: Attribute {   private string FamilyName;   private string GivenName;   public AuthorAttribute(string FamilyName)   {     this.FamilyName = FamilyName;   }   public override String ToString()   {     return String.Format("Author: {0} {1}",                           Family, Given);   }   public string Family   {     get     {        return FamilyName;     }     set     {        FamilyName = value;     }   }   public string Given   {     get     {        return GivenName;     }     set     {        GivenName = value;     }   } } [Author("Watkins", Given = "Damien")] [Author("Abrams")] public class AttributeSample {   [Author("Hammond", Given = "Mark")]   public static void Main()   {     Type t = typeof(AttributeSample);     object[] attributes = t.GetCustomAttributes(true);     Console.WriteLine("Custom Attributes are: ");     foreach(Object o in attributes)     {       System.Console.WriteLine("\t{0}", o);     }   } } 

The first class defined in Listing 3.4, AuthorAttribute , is a user-defined custom attribute. This fact is implied by its inheritance specification, in which it inherits from the Attribute class. The new class contains two fields, String s that represent the author's family and given names . It contains two methods and a constructor that specifies that at least the family name must be supplied. The class also overrides the ToString method it inherits from Object . From the class's definition, you may wonder how the FirstName member is ever assigned a value. The member can be accessed in a manner similar to a named parameter in languages that support this concept. An example of this type of usage is shown later in the file.

The next class defined in Listing 3.4 is a C# class called AttributeSample . Its definition is preceded by two custom attributes of type Author , the program's user-defined custom attribute class. These attributes annotate the class AttributeSample and, in effect, indicate that two authors were responsible for writing this class. The first custom attribute uses the name of the member FirstName to assign a value to that member. The Main method in the AttributeSample class is also annotated with a single instance of the user-defined attribute class, this time designating the author of this method. The Main method in the AttributeSample class uses the GetCustomAttributes method to access an array of custom attributes for this class and then displays them on the screen. It produces the following output:

 Custom Attributes are:          Author: Abrams         Author: Watkins Damien 

The custom attribute for the author of the Main method is not shown, as the program gets only the attributes for the class. Extending the program to get the attributes for the method is a simple matter. Also, note that even though one method in the class is annotated, the other methods do not have to be.

If you open the executable program with ILDASM (see Figure 3.3), you can see the user-defined attribute class. In addition, you can see how instances of this class are persisted in the metadata.

Figure 3.3. Reviewing the custom attributes created in Listing 3.4

graphics/03fig03.gif

Standard Attributes

Although you can define your own attributes, the Framework Class Library provides a number of predefined standard attributes, including those shown in Figure 3.4. All the types that inherit from System.Attribute in Figure 3.4 end with the suffix Attribute ”for example, WebMethod-Attribute . For brevity, the word "Attribute" is omitted in the figure. Likewise, as you saw in Listing 3.4, the C# compiler permits developers to omit the Attribute suffix in source code.

Figure 3.4. Selected standard attributes predefined by the BCL

graphics/03fig04.gif

Listing 3.5 demonstrates the use of one of the standard attributes, ObsoleteAttribute . The "Obsolete" part of the name indicates that a program element, such as a type or method, should no longer be used. For example, one method may be superceded by another method in a subsequent version of a type. In this situation, the developer may continue to provide both methods to avoid breaking clients using the original method but document to clients that they should use the newer method. To do so, the developer can apply the Obsolete attribute to the method. Then every time a client is compiled that uses the original method, a warning or an error is raised. In Listing 3.5, OldMethod has been superceded by NewMethod . In this case, using OldMethod is not really an error, so only a warning is generated if a client calls this method.

Listing 3.5 Using a standard attribute: ObsoleteAttribute
 using System; namespace Sample {   public class TestClass   {     [Obsolete("Use NewMethod instead of OldMethod")]     public static void OldMethod()     {       Console.WriteLine("Hi World");     }     public static void NewMethod()     {       Console.WriteLine("Hello World");     }   } } 

The following Visual Basic code uses the Obsolete method:

 Imports System  Module MyModule   Sub Main()     Sample.TestClass.OldMethod()   End Sub End Module 

Compiling the Visual Basic program generates the following output:

 Microsoft (R) Visual Basic .NET Compiler version 7.00.9466  for Microsoft (R) .NET Framework version 1.00.3705.209 Copyright (C) Microsoft Corporation 1987-2001. All rights reserved. C:\Project7\Demos\Obsolete\Obsolete.vb(4) : warning BC40000: 'Public Shared Overloads Sub OldMethod()' is obsolete: 'Use NewMthod instead of OldMethod'     Sample.TestClass.OldMethod()     ~~~~~~~~~~~~~~~~~~~~~~~~~~ 

Listing 3.6 demonstrates the use of another standard attribute, DllImportAttribute . In this program, the developer wants to access the ASCII version of the MessageBox method found in user32.dll . The DllImportAttribute annotates a method's prototype ”in this example, MessageBoxA ”by stating that the method body can be found in user32.dll so no definition of the method is provided in the Sample class. Any call to this method will result in the marshaling of parameters, if required, and then the invocation of the MessageBoxA method.

Listing 3.6 Using a standard attribute: DllImportAttribute
 using System; using System.Runtime.InteropServices; class Sample {    [DllImport("user32.dll")]    public static extern int       MessageBoxA(int p, string m, string h, int t);    public static int Main()    {       return MessageBoxA(0, "Hello World!",                          "DLLImport Sample", 0);    } } 

Executing the program given in Listing 3.6 produces the dialog box shown in Figure 3.5.

Figure 3.5. Output of Listing 3.6

graphics/03fig05.gif



Programming in the .NET Environment
Programming in the .NET Environment
ISBN: 0201770180
EAN: 2147483647
Year: 2002
Pages: 146

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