Interesting question: can you use Reflection. Emit to generate this code? (Answer)

Source: Internet
Author: User
Tags emit

In my previous blog, I raised a question: how to use. NET Reflection. Emit to generate three types equivalent to the following VB code:

Class A    Implements B.IEnd ClassClass B    Inherits A    Interface I    End InterfaceEnd Class

The difficulty of this problem lies in the three types of circular dependency: A implements interface B. therefore, A depends on I; B is A subclass of A, so B depends on A; interface I is A nested type of B, so I depends on B. The biggest problem when using Reflection. Emit is that the CreateType method is called in whatever order, there will always be a dependency error. The following is a simple attempt but cannot be successful:

Module Program    Sub Main()        Dim name = New AssemblyName("test")        Dim dasm = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave)        Dim dmod = dasm.DefineDynamicModule(name.Name, name.Name + ".dll")        Dim tA = dmod.DefineType("A", TypeAttributes.Public Or TypeAttributes.Class)        Dim tB = dmod.DefineType("B", TypeAttributes.Public Or TypeAttributes.Class, tA)        Dim tI = tB.DefineNestedType("I", TypeAttributes.NestedPublic Or TypeAttributes.Interface Or TypeAttributes.Abstract)        tA.AddInterfaceImplementation(tI)        tA.CreateType()        tB.CreateType()        tI.CreateType()        dasm.Save(name.Name + ".dll")    End SubEnd Module

We found that the main problems here are:

  1. Reflection. Emit cannot generate B-Type constructor in this case
  2. A type parsing error occurs when you create a type.

Therefore, we solve these two problems respectively. First, since the constructor of B cannot be automatically generated, we can create it manually. This can be done using DefineConstructor of TypeBuilder. As the base class of type A is an Object, use definedefaconconstructor directly. Note that constructor has many required attributes, including PrivateScope, HideBySig, SpecialName, and RTSpecialName. They must be added (otherwise, many errors may occur when using it ). The next step is the issue that cannot be found due to loop reference. We can handle the TypeResolve event of AppDomain to manually handle the issue of loop reference. The following is a complete solution:

Imports System.ReflectionImports System.Reflection.EmitModule Program    Sub Main()        Dim name = New AssemblyName("test")        Dim dasm = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave)        Dim dmod = dasm.DefineDynamicModule(name.Name, name.Name + ".dll")        Dim tA = dmod.DefineType("A", TypeAttributes.Public Or TypeAttributes.Class)        Dim tB = dmod.DefineType("B", TypeAttributes.Public Or TypeAttributes.Class, tA)        Dim tI = tB.DefineNestedType("I", TypeAttributes.NestedPublic Or TypeAttributes.Interface Or TypeAttributes.Abstract)        tA.AddInterfaceImplementation(tI)        Const ctorAttr As MethodAttributes = MethodAttributes.Public Or MethodAttributes.PrivateScope Or            MethodAttributes.HideBySig Or MethodAttributes.SpecialName Or MethodAttributes.RTSpecialName        Dim ctorA = tA.DefineDefaultConstructor(ctorAttr)        Dim ctorB = tB.DefineConstructor(ctorAttr,                                         CallingConventions.Standard, {})        With ctorB.GetILGenerator            .Emit(OpCodes.Ldarg_0)            .Emit(OpCodes.Call, ctorA)            .Emit(OpCodes.Ret)        End With        AddHandler AppDomain.CurrentDomain.TypeResolve,            Function(sender As Object, e As ResolveEventArgs)                Select Case e.Name                    Case "A" : Return tA.CreateType.Assembly                    Case "B" : Return tB.CreateType.Assembly                    Case "I" : Return tI.CreateType.Assembly                End Select                Return Nothing            End Function        tA.CreateType()        tB.CreateType()        tI.CreateType()        dasm.Save(name.Name + ".dll")    End SubEnd Module

The generated assembly is correct, whether through Reflector decompilation or using C #/VB for reference. It is the same as that compiled by the true VB compiler.

The reason for this problem is that the PM Lucian Wischick blog of VB Team raised this question. Microsoft's VB Team is porting the VB compiler written in C ++ into VB code. They are studying whether the backend hosting compiler can be implemented using Reflection. Emit. VB supports the code of this type of loop dependency, so they have a headache. Fortunately, a reply solved this problem. If you want to use Reflection. Emit as the compiler backend, you can refer to this method.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.