【问题标题】:ILGenerator.DeclareLocal() takes a type of a class not yet compiledILGenerator.DeclareLocal() 采用尚未编译的类的类型
【发布时间】:2012-09-14 22:54:56
【问题描述】:

在为自己的语言制作编译器的过程中,我尝试使用 Reflection.Emit 框架生成一些 MSIL 代码。当我声明局部变量时使用int 时效果很好。但是,当我想声明一个尚未编译的类型的局部变量时,我遇到了麻烦,因为DeclareLocal()Type 作为参数。那是我未编译的类,比如A,仍然需要使用

来定义
 assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemName, AssemblyBuilderAccess.RunAndSave);
 module = assemblyBuilder.DefineDynamicModule(Filename); 
 module.DefineType(name, TypeAttributes.Public | TypeAttributes.Class)

那么我将如何编译以下程序

class A {
    void M() { B b = new B(); }
}
class B
    void M() { A a = new A(); }
}

【问题讨论】:

  • @phoog:他还不如等人来做他的工作,然后..
  • 我实际上并没有在这里做 C#.. 这只是循环依赖的一个例子
  • 语言通常要求在使用之前知道声明。 Pascal 和 C++ 就是很好的例子。如果你不想要这个限制,那么你需要创建一个多通道编译器。
  • @Hans 我不确定使用 Reflection.Emit 框架如何实现这一点。我需要生成一个类,以便在进行调用和分配时可以引用它的 TYPE。但是对于上述循环定义,这两个类中的任何一个都不会在另一个之前完全构造。
  • 您可以通过在遇到类型但尚未发出该类型时生成代码来修复它。您最终可能会嵌套好几层。

标签: c# compiler-construction cil reflection.emit


【解决方案1】:

您在这里需要的主要见解是TypeBuilder 派生自Type。所以,即使你还没有最终确定一个类型(通过调用CreateType()),你也可以用它来声明另一个类型的局部变量。

我遇到的另一个障碍是未完成的TypeBuilder 上的GetConstructor() 不起作用(它会引发异常)。但是如果你显式创建默认构造函数,你可以通过ConstructorBuilder调用它。

static void Main()
{
    var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
        new AssemblyName("foo"), AssemblyBuilderAccess.RunAndSave);
    var module = assemblyBuilder.DefineDynamicModule("foo.dll");
    var aType = module.DefineType(
        "A", TypeAttributes.Public | TypeAttributes.Class);
    var bType = module.DefineType(
        "B", TypeAttributes.Public | TypeAttributes.Class);
    var aCtor = aType.DefineDefaultConstructor(MethodAttributes.Public);
    var bCtor = bType.DefineDefaultConstructor(MethodAttributes.Public);
    CreateMethodM(aType, bType, bCtor);
    CreateMethodM(bType, aType, aCtor);
    aType.CreateType();
    bType.CreateType();
    assemblyBuilder.Save("foo.dll");
}

static void CreateMethodM(
    TypeBuilder thisType, Type otherType, ConstructorInfo otherCtor)
{
    var method = thisType.DefineMethod(
        "M", MethodAttributes.Private, typeof(void), Type.EmptyTypes);
    var il = method.GetILGenerator();
    var local = il.DeclareLocal(otherType);
    il.Emit(OpCodes.Newobj, otherCtor);
    il.Emit(OpCodes.Stloc, local);
    il.Emit(OpCodes.Ret);
}

【讨论】:

  • 啊!我的解决方案与您的解决方案非常接近!我想调用“t.DeclaringType”而不是简单的“t”而蒙蔽了双眼
  • DeclaringType 是不同的,它代表这个类型被声明的类型,例如当它是一个嵌套类型时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多