Reflection and Reflection.Emit in VB.NET Part 2

In this article I will explain you about Reflection and Reflection.Emit in VB.NET.
  • 2121
 

Read Part 1

Here, some more discussion with an example of Reflection and Reflection.Emit. You should use Reflection.Emit members for the following reasons:

  • You have your own macro languages, compilers, or script compilers in your applications.

  • You want to improve performance of your algorithms by creating assemblies, classes, modules, and new types during runtime.

  • You want to improve performance of late-bound objects. You can emit the code necessary to call bound types directly, and then call through your emitted method. Although you cannot perform calls as speedily as with early binding, you will perform better than late binding.

The System.Reflection.Emit namespace provides the classes necessary for a user to create an .exe file on the fly. Its classes allow a compiler or tool to emit metadata and MSIL. So you can create .exe files on your disk on the fly as if you were running the code, saving it, and calling the compiler to compile the code. Mostly you will need this feature and this namespace for your custom script engines and compilers.

The Reflection.Emit namespace has many members you can use for emitting. Here are the two most important ones:

  • The AssemblyBuilder class is the starting point for any application that emits code at runtime and has methods for creating dynamic modules.

  • The ModuleBuilder class is used as the starting point for adding types such as classes and structures to a dynamic assembly at runtime.

There is a more sophisticated example that shows how to emit an assembly that contains a method to calculate a factorial on the fly.

Example of Calculating Factorial by Emitting Operation Codes (emitfactorial.vb)

    Imports System.Reflection
    Imports System.Reflection.Emit
    Imports System.IO
    Imports System.Threading
    Imports System.Diagnostics

    ' declare the interface
    Public Interface IFactorial
        Function myfactorial() As Integer
    End
Interface

    Public
Class SampleFactorialFromEmission

        ' emit the assembly using op codes
        Private Function EmitAssembly(ByVal theValue As Integer) As Assembly

            ' create assembly name
            Dim assemblyName As New AssemblyName()
            assemblyName.Name =
"FactorialAssembly"

            ' create assembly with one module
            Dim newAssembly As AssemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run)
            Dim newModule As ModuleBuilder = newAssembly.DefineDynamicModule("MFactorial")

            ' define a public class named "CFactorial" in the assembly
            Dim myType As TypeBuilder = newModule.DefineType("CFactorial", TypeAttributes.[Public])

            ' Mark the class as implementing IFactorial.
            myType.AddInterfaceImplementation(GetType(IFactorial))

            ' define myfactorial method by passing an array that defines
            ' the types of the parameters, the type of the return type,
            ' the name of the method, and the method attributes.
            Dim paramTypes As Type() = New Type(-1) {}
            Dim returnType As Type = GetType(Int32)
            Dim simpleMethod As MethodBuilder = myType.DefineMethod("myfactorial", MethodAttributes.[Public]_
            
Or MethodAttributes.Virtual, returnType, paramTypes)

            ' obtain an ILGenerator to emit the IL
            Dim generator As ILGenerator = simpleMethod.GetILGenerator()

            ' Ldc_I4 pushes a supplied value of type int32
            ' onto the evaluation stack as an int32.
            ' push 1 onto the evaluation stack.
            ' foreach i less than theValue,
            ' push i onto the stack as a constant
            ' multiply the two values at the top of the stack.
            ' The result multiplication is pushed onto the evaluation
            ' stack.
            generator.Emit(OpCodes.Ldc_I4, 1)
            For i As Int32 = 1 To theValue
                generator.Emit(
OpCodes.Ldc_I4, i)
                generator.Emit(
OpCodes.Mul)
            Next

            ' emit the return value on the top of the evaluation stack.
            ' Ret returns from method, possibly returning a value.
            generator.Emit(OpCodes.Ret)

            ' encapsulate information about the method and
            ' provide access to the method metadata
            Dim factorialInfo As MethodInfo = GetType(IFactorial).GetMethod("myfactorial")

            ' specify the method implementation.
            ' pass in the MethodBuilder that was returned
            ' by calling DefineMethod and the methodInfo just created
            myType.DefineMethodOverride(simpleMethod, factorialInfo)

            ' create the type and return new on-the-fly assembly
            myType.CreateType()
            Return newAssembly
        End Function

        ' check if the interface is null, generate assembly
        ' otherwise it is already there, where it is to be...
        Public Function DoFactorial(ByVal theValue As Integer) As Double
            If
thesample Is Nothing Then
                GenerateCode(theValue)
            End If

            ' call the method through the interface
            Return (thesample.myfactorial())
        End Function

        ' emit the assembly, create an instance and
        ' get the interface IFactorial
        Public Sub GenerateCode(ByVal theValue As Integer)
            Dim theAssembly As Assembly = EmitAssembly(theValue)
            thesample =
DirectCast(theAssembly.CreateInstance("CFactorial"), IFactorial)
        End Sub

        ' private member data
        Private thesample As IFactorial = Nothing
    End
Class

    Class
Class1
    <STAThread()> _
        Shared Sub Main(ByVal args As String())
            Dim aValue As Int32 = 5
            Dim t As New SampleFactorialFromEmission()
            Dim result As Double = t.DoFactorial(aValue)
            Console.WriteLine("Factorial of " & aValue & " is " & result)
            Console.ReadLine()
        End Sub
    End
Class

Output

emit1.gif
 

Conclusion

Hope this article would have helped you in understanding the Reflection and Reflection.Emit in VB.NET.

Categories

More Articles

© 2020 DotNetHeaven. All rights reserved.