8

自分の言語用のコンパイラの作成をいじくりまわしながら、Reflection.Emit フレームワークを使用して MSIL コードを生成しようとしています。intローカル変数を宣言するときに使用すると正常に機能します。ただし、まだコンパイルしていない型のローカル変数を宣言したい場合は、 as 引数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(); }
}
4

1 に答える 1

8

ここで必要な主な洞察は、TypeBuilderから派生したものTypeです。したがって、( を呼び出して) まだ型を確定していなくても、CreateType()それを使用して別の型でローカル変数を宣言できます。

私が遭遇したもう 1 つの障害はGetConstructor()、未完成TypeBuilderでは機能しない (例外がスローされる) ことです。ただし、デフォルトのコンストラクターを明示的に作成する場合は、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);
}
于 2012-09-14T23:35:49.010 に答える