Emitting Attributes to IL

You can use Reflection to emit IL directly. (Refer to Chapter 4 for more information on Reflection in general.) IL is an intermediate form similar to Java byte code that is created between the compile and link processes. By emitting IL the CLR has one more opportunity to perform security checks, and the number of compilers that have to be created is dramatically reduced. For example, if Borland implements a .NET compiler for Delphi, Borland has to implement only one compiler to emit IL. Then any existing linker can be used to write the emitted IL to a particular platform. Without IL, vendors would have to write a compiler for each language and operating system. With IL, each vendor needs to compile only to IL, and then one specific operating system vendor's linker can be used to convert the IL to machine language for that operating system, regardless of the originating language.

When you write emitters , you need to emit as IL all the entities you would write in Visual Basic .NET. This includes attributes. Listing 5.11 implements an emitter that emits the equivalent of a Hello, World! application, demonstrating how to emit attributes and other entities. (The emitted IL is shown in Figure 5.3.)

Listing 5.11 Defining an Emitter That Creates a Console Application
 1:  Imports System 2:  Imports System.Reflection 3:  Imports System.Reflection.Emit 4: 5:  Public Class EmitAttributeDemo 6: 7:    Public Shared Sub Main(ByVal Args() As String) 8:      Emitter.Run() 9:    End Sub 10: 11: End Class 12: 13: Public Class Emitter 14: 15:   Public Shared Sub Run() 16:     Dim E As Emitter = New Emitter() 17:     E.Emit() 18:   End Sub 19: 20:   Private AssemblyName As AssemblyName 21:   Private AssemblyBuilder As AssemblyBuilder 22:   Private ModuleBuilder As ModuleBuilder 23:   Private TypeBuilder As TypeBuilder 24:   Private MethodBuilder As MethodBuilder 25: 26:   Public Sub Emit() 27:     Const Name As String = "Hello.exe" 28:     AssemblyName = New AssemblyName() 29:     AssemblyName.Name = "Hello" 30: 31:     AssemblyBuilder = AppDomain.CurrentDomain. _ 32:       DefineDynamicAssembly(AssemblyName, _ 33:       AssemblyBuilderAccess.Save) 34: 35:     ModuleBuilder = AssemblyBuilder.DefineDynamicModule( _ 36:       "Class1.mod", Name, False) 37: 38:     TypeBuilder = ModuleBuilder.DefineType("Class1") 39: 40:     MethodBuilder = TypeBuilder.DefineMethod("Main", _ 41:       MethodAttributes.Private Or MethodAttributes.Static _ 42:       Or MethodAttributes.HideBySig, _ 43:       CallingConventions.Standard, Nothing, _ 44:       New Type() {GetType(System.String())}) 45: 46:     Dim CustomAttributeBuilder As CustomAttributeBuilder = _ 47:       New CustomAttributeBuilder( _ 48:       GetType(System.STAThreadAttribute).GetConstructor( _ 49:       New Type() {}), New Object() {}) 50: 51:     MethodBuilder.SetCustomAttribute(CustomAttributeBuilder) 52: 53:     AssemblyBuilder.SetEntryPoint(MethodBuilder) 54: 55:     Dim Generator As ILGenerator = MethodBuilder.GetILGenerator() 56:     Generator.Emit(OpCodes.Ldstr, "Hello, World!") 57: 58:     Dim MethodInfo As MethodInfo = GetType(System.Console).GetMethod( _ 59:       "WriteLine", BindingFlags.Public Or BindingFlags.Static, _ 60:       Nothing, New Type() {GetType(String)}, Nothing) 61: 62:     Generator.Emit(OpCodes.Call, MethodInfo) 63:     Generator.Emit(OpCodes.Ret) 64: 65:     TypeBuilder.CreateType() 66:     AssemblyBuilder.Save(Name) 67: 68:   End Sub 69: 70: End Class 
Figure 5.3. The emitted IL created by the code in Listing 5.11, which can be viewed using the ildasm.exe utility.

graphics/05fig03.gif

When you program, you create a solution and a project and define types that have members. When you write an emitter, you have to write code that emits analogous elements. For example, you need to emit an assembly and that assembly will have modules. Each module will have types, and those types will have members . The ability to emit these elements is captured in builder classes defined in the System.Reflection.Emit namespace. For example, if you want to emit an assembly, you need an AssemblyBuilder , and types are emitted with TypeBuilder objects.

Each of these builders are hierarchically dependent. For example, assemblies exist in AppDomains and are therefore requested from AppDomains . Lines 31 through 33 in Listing 5.11 demonstrate how to request a dynamic assembly. From the assembly we request a module in the form of a ModuleBuilder , shown on lines 35 and 36. Emitters progress this way until we get to individual lines of code.

Lines 46 through 51 demonstrate how to create and emit an attribute. The first thing we need to do is get the Type object for the attribute we want to emit. Then from the Type object we can request its constructor. Both of these steps are defined in lines 48 and 49. From the ConstructorInfo object requested we can create an instance of the System.Reflection.Emit.CustomAttributeBuilder object. To apply the attribute we invoke the SetCustomAttribute method on the builder that represents the entity we want to apply the attribute to. Line 51 applies the attribute represented by the MethodBuilder . Also, the STAThreadAttribute is applied to the Main method for the console application.

Here is a recap of the steps necessary to emit an attribute.

  1. Obtain a Type object for the type of the attribute you want to emit.

  2. Request a ConstructorInfo object for that attribute's type, invoking Type.GetConstructor .

  3. Create a new instance of the CustomAttributeBuilder , passing the ConstructorInfo object to the constructor for the CustomAttributeBuilder .

  4. Invoke Entity Builder.SetCustomAttribute , passing the CustomAttributeBuilder to the SetCustomAttribute method. ( Entity represents an instance of a Builder class, such as Method in MethodBuilder .)



Visual Basic. NET Power Coding
Visual Basic(R) .NET Power Coding
ISBN: 0672324075
EAN: 2147483647
Year: 2005
Pages: 215
Authors: Paul Kimmel

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