Logo
programming4us
programming4us
programming4us
programming4us
Windows XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
 
programming4us
Windows 7

Visual Basic 2010 : Reflection - Generating Code at Runtime with Reflection.Emit

6/20/2011 2:56:38 PM
The System.Reflection.Emit namespace provides objects for generating assemblies, types, and type members at runtime. Basically you need to perform the following operations sequentially:

1.
Create an in-memory assembly within the current application domain with an instance of the AssemblyBuilder class.

2.
Create a module for containing types via an instance of the ModuleBuilder class.

3.
Create types with instances of the TypeBuilder class.

4.
Add members to the TypeBuilder via XBuilder objects, such as MethodBuilder, FieldBuilder, and PropertyBuilder.

5.
Save the assembly to disk if required.

The code in Listing 1 demonstrates how to create dynamically a simple implementation of the Person class with one property and one method.

Listing 1. Generating Code at Runtime
Imports System.Reflection
Imports System.Reflection.Emit

Module CreatingCode

Sub CreateAssembly()

'Creates assembly name and properties
Dim asmName As New AssemblyName("People")
asmName.Version = New Version("1.0.0")
asmName.CultureInfo = New Globalization.CultureInfo("en-US")

'Gets the current application domain
Dim currentAppDomain As AppDomain = AppDomain.CurrentDomain

'Creates a new in-memory assembly in the current application domain
'providing execution and saving capabilities
Dim asmBuilder As AssemblyBuilder = currentAppDomain.
DefineDynamicAssembly(asmName,
AssemblyBuilderAccess.RunAndSave)

'Creates a module for containing types
Dim modBuilder As ModuleBuilder = _
asmBuilder.DefineDynamicModule("PersonModule",
"People.dll")

'Creates a type, specifically a Public Class
Dim tyBuilder As TypeBuilder = _
modBuilder.DefineType("Person",
TypeAttributes.Public _
Or TypeAttributes.Class)
'Defines a default empty constructor
Dim ctorBuilder As ConstructorBuilder = _
tyBuilder.DefineDefaultConstructor(MethodAttributes.Public)

'Defines a field for storing a property value
Dim fldBuilder As FieldBuilder = _
tyBuilder.DefineField("_lastName",
GetType(String),
FieldAttributes.Private)

'Defines a property of type String
Dim propBuilder As PropertyBuilder = _
tyBuilder.DefineProperty("LastName",
PropertyAttributes.None, GetType(String),
Type.EmptyTypes)

'Defines a series of attributes for both getter and setter
Dim propMethodAttributes As MethodAttributes = _
MethodAttributes.Public Or
MethodAttributes.SpecialName Or
MethodAttributes.HideBySig

'Defines the getter method for the property
Dim propGetMethod As MethodBuilder = _
tyBuilder.DefineMethod("get_LastName",
propMethodAttributes,
GetType(String),
Type.EmptyTypes)
'Generates IL code for returning the field value
Dim propGetMethodIL As ILGenerator = propGetMethod.GetILGenerator
propGetMethodIL.Emit(OpCodes.Ldarg_0)
propGetMethodIL.Emit(OpCodes.Ldfld, fldBuilder)
propGetMethodIL.Emit(OpCodes.Ret)

'Defines the setter method for the property
Dim propSetMethod As MethodBuilder = _
tyBuilder.DefineMethod("set_LastName",
propMethodAttributes,
GetType(String),
Type.EmptyTypes)

'Generates the IL code for setting the field value
Dim propSetMethodIL As ILGenerator = propSetMethod.GetILGenerator
propSetMethodIL.Emit(OpCodes.Ldarg_0)
propSetMethodIL.Emit(OpCodes.Ldarg_1)
propSetMethodIL.Emit(OpCodes.Stfld, fldBuilder)
propSetMethodIL.Emit(OpCodes.Ret)

'Assigns getter and setter to the property
propBuilder.SetGetMethod(propGetMethod)
propBuilder.SetSetMethod(propSetMethod)

'Defines a public method that returns String
Dim methBuilder As MethodBuilder = _
tyBuilder.DefineMethod("BuildFullName",
MethodAttributes.Public,
GetType(String),
Type.EmptyTypes)

'Method body cannot be empty, so just return
Dim methodILGen As ILGenerator = methBuilder.GetILGenerator
methodILGen.EmitWriteLine("Method implementation needed")
methodILGen.Emit(OpCodes.Ret)

'Creates an instance of the type
Dim pers As Type = tyBuilder.CreateType

'Enumerates members for demo purposes
For Each member In pers.GetMembers
Console.WriteLine("Member name: {0}", member.Name)
Next

'Saves the assembly to disk
asmBuilder.Save("People.dll")
Console.ReadLine()
End Sub
End Module


After you create an AssemblyName for assigning assembly properties and get the instance of the current application domain, you use the AppDomain.DefineDynamicAssembly method to generate an in-memory assembly. The method returns an instance of the AssemblyBuilder class and receives the AssemblyName instance and a value from the AssemblyBuilderAccess enumeration that establishes the access level for Reflection. RunAndSave enables executing and saving the assembly, but you can also limit Reflection with the ReflectionOnly value. The next step is creating an instance of the ModuleBuilder class that can act as a container of types. This is accomplished by invoking the AssemblyBuilder.DefineDynamicModule method that requires you to specify the module name and the filename. (This one should be the same as for AssemblyName if you want metadata to be merged into a single assembly.) When you have a module, you can put your types into it. For each type you need to create an instance of the TypeBuilder class, which you accomplish by invoking the ModuleBuilder.DefineType method that receives the type name and qualifiers as arguments. Qualifiers are one or more values from the TypeAttributes enumeration; in the current example, Public and Class values are assigned to the new type to create a new class with public visibility. The TypeBuilder class provides lots of methods for adding members, such as constructors, field, properties, and methods. For constructors, the code demonstrates how to add a public, empty, and default constructor invoking the TypeBuilder.DefineDefaultConstructor, but you can supply constructor overloads via the DefineConstructor method. To implement properties, you first need to supply fields. These are implemented via the TypeBuilder.DefineField method that requires three arguments: the field name, the type (retrieved via GetType), and qualifiers, determined with values from the FieldAttributes enumeration. Similarly you implement properties invoking the TypeBuilder.DefineProperty method, but this is not enough because you also need to explicitly generate the getter and setter methods for each property. These are special methods that require providing some properties defined within the propMethodAttributes variable that takes values from the MethodAttributes enumeration. When you establish method attributes, you create two MethodBuilder instances. Such a class generates each kind of method, including special ones. You just supply the method name, attributes, the return type, and an array of type parameters. The actual problem is how you implement method bodies. As a general rule, methods implemented via Reflection cannot have an empty method body, so you must provide some Intermediate Language code to populate the method body. This is accomplished by invoking methods from the ILGenerator class that enable injecting IL code to the method. Consider the following snippet, excerpted from Listing 1:

'Generates IL code for returning the field value
Dim propGetMethodIL As ILGenerator = propGetMethod.GetILGenerator
propGetMethodIL.Emit(OpCodes.Ldarg_0)
propGetMethodIL.Emit(OpCodes.Ldfld, fldBuilder)
propGetMethodIL.Emit(OpCodes.Ret)

The MethodBuilder.GetILGenerator method returns an instance of the ILGenerator class. Then you invoke the Emit method to execute IL code. In the preceding snippet, the IL code simply returns the value of the fldBuilder variable and pushes the value onto the stack and then returns. Actions to execute via the IL are taken via shared fields from the OpCodes class, each related to an IL instruction.

Note on Opcodes

Reflection is powerful, but because you need to know the MS Intermediate Language in detail before implementing dynamic code, and because this would be beyond of scope in this book, you should look at the appropriate MSDN documentation at http://msdn.microsoft.com/en-us/library/8ffc3x75(VS.100).aspx.


When you provide the method body for getters and setters, you add them to the related properties via the PropertyBuilder.SetGetMethod and PropertyBuilder.SetSetMethod methods. Similarly you implement any other method, and the sample code demonstrates this by providing a simple method body that invokes EmitWriteLine, a method that sends to the assembly the appropriate IL code for writing a message to the Console window. Finally you simply invoke AssemblyBuilder.Save to save the assembly to disk. More than running the code, you can ensure if everything works by inspecting the assembly with a Reflection tool such as Microsoft IL Disassembler. Figure 1 shows how the assembly looks if opened with ILDasm, demonstrating the correct result of our work.

Figure 1. The assembly created at runtime opened in IL Disassembler.

Typically you will prefer code generators instead of Reflection to generate code on-the-fly because in that case you do not need to know about Intermediate Language.

Late Binding Concepts

Late binding is a particular programming technique that you use to resolve types at runtime and for types dynamic loading that is accomplished by assigning objects to variable of type Object. For a better understanding, consider its counterpart, the early binding. This happens at compile time where the compiler checks that argument types utilized to invoke methods match their signatures. An example is the background compiler that provides real-time check for types used in code, thanks to early binding. On the contrary, late binding requires you to specify the function signatures; moreover you must ensure that the code uses the correct types. Basically this means that binding requirements, such as binary files to load or methods to invoke, is long delayed, in many cases until before the method is invoked. Reflection greatly uses late binding because in many cases you work with objects of type Object, and this requires late resolution for invoking appropriate members. The following example, although not related to Reflection, demonstrates how to invoke members from objects declared as Object that are instead of different types, but this is determined late at runtime:

' This code creates an instance of Microsoft Excel and adds a new WorkBook.
' Requires Option Strict Off
Sub LateBindingDemo()
Dim xlsApp As Object
Dim xlsBook As Object
xlsApp = CreateObject("Excel.Application")
xlsBook = xlsApp.Workbooks.Add
End Sub

Option Strict Off Best Practices

Because in lots of situations turning Option Strict to Off can be very dangerous, if you need to work with late-binding you should consider moving the code that requires such a technique to a separate code file and just mark this code file with Option Strict Off, instead of setting it Off at the project level.


As you can see, invoking members from Object in late binding is different because the compiler cannot predetermine if members exist, and you don’t have IntelliSense support. But if the actual type defines members that you are attempting to invoke, they will be correctly bound at runtime. Just remember that late binding requires an Option Strict Off directive and that should be used carefully.

Other -----------------
- Visual Basic 2010 : Reflection - Invoking Code Dynamically
- Visual Basic 2010 : Reflection - Reflecting Types
- Administering Internet Explorer : Troubleshooting Internet Explorer Issues
- Administering Internet Explorer : Understanding Advanced Settings (part 2) - Branding Internet Explorer & Group Policy Settings
- Administering Internet Explorer : Understanding Advanced Settings (part 1) - Certificate Settings
- Administering Internet Explorer : Managing Windows Internet Explorer Settings (part 2)
- Administering Internet Explorer : Managing Windows Internet Explorer Settings (part 1) - Managing Cache
- Visual Basic 2010 : Reflection - Understanding Assemblies Metadata & Getting Assembly Information
- Visual Basic 2010 : Hosting WCF Services in Internet Information Services & Configuring Services with the Configuration Editor
- Supporting Mobile Windows 7 Users : Understanding DirectAccess & Using BranchCache
 
 
Video tutorials
- How To Install Windows 8 On VMware Workstation 9

- How To Install Windows 8

- How To Install Windows Server 2012

- How To Disable Windows 8 Metro UI

- How To Change Account Picture In Windows 8

- How To Unlock Administrator Account in Windows 8

- How To Restart, Log Off And Shutdown Windows 8

- How To Login To Skype Using A Microsoft Account

- How To Enable Aero Glass Effect In Windows 8

- How To Disable Windows Update in Windows 8

- How To Disable Windows 8 Metro UI

- How To Add Widgets To Windows 8 Lock Screen
programming4us programming4us
Popular tags
Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 windows Phone 7 windows Phone 8
programming4us programming4us
 
Popular keywords
HOW TO Swimlane in Visio Visio sort key Pen and Touch Creating groups in Windows Server Raid in Windows Server Exchange 2010 maintenance Exchange server mail enabled groups Debugging Tools Collaborating
programming4us programming4us
 
programming4us
Girls
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone