Конструктор, связывающий с Reflection.Emit / Sigil - PullRequest
0 голосов
/ 08 мая 2018

Я пытаюсь создать класс, подобный следующему, используя Sigil , который является оболочкой для Reflection.Emit.

public class Test
{
    public Test(string arg1)
    {
    }

    public Test() : this("arg1") 
    {
    }
} 

Используя следующий код, я получаю исключение: «Вызванный элемент не поддерживается до создания типа».

using System;
using System.Reflection;
using System.Reflection.Emit;
using Sigil.NonGeneric;

public class Program
{
    public static void Main()
    {
        var asmName = new AssemblyName("MyAssembly");
        var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Save);

        var mod = asm.DefineDynamicModule(asmName.Name, asmName.Name + ".dll");

        var test = mod.DefineType("Test", TypeAttributes.Public);

        // special constructor
        var ctorBuilder1 = Emit.BuildConstructor(new Type[] { typeof(string) }, test, MethodAttributes.Public);
        ctorBuilder1.Return();
        var ctor1 = ctorBuilder1.CreateConstructor();

        // default constructor calling the special one
        var ctorBuilder2 = Emit.BuildConstructor(new Type[] { }, test, MethodAttributes.Public);
        ctorBuilder2.LoadArgument(0);
        ctorBuilder2.LoadConstant("arg1");
        ctorBuilder2.Call(ctor1); // Exception thrown here
        ctorBuilder2.Return();
        var ctor2 = ctorBuilder2.CreateConstructor();

        test.CreateType();
        asm.Save(asmName.Name + ".dll");
    }
}

Я читал об использовании «DynamicMethod», но получил ошибку «Делегат типа Sigil.Impl.NonGenericPlaceholderDelegate не принимает параметры», когда я заменил свой вызов BuildConstructor следующим:

var piCtor = Emit.NewDynamicMethod(pi, new Type[] {}, ".ctor", mod);

Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 08 мая 2018

Похоже, на данный момент как минимум Sigil.NonGeneric не справляется с этим должным образом.Тем не менее, похоже, что вы можете смешивать и сопоставлять Sigil с кодом не-Sigil.

Таким образом, вы можете изменить просто ваш ctorBuilder2 код для использования встроенного кода Reflection.Emit.:

var ctorBuilder2 = test.DefineConstructor(MethodAttributes.Public,
    CallingConventions.Standard, new Type[0]);
var generator = ctorBuilder2.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldstr, "arg1");
generator.Emit(OpCodes.Call, ctor1);
generator.Emit(OpCodes.Ret);

Похоже, что сборка будет построена так, как вам нужно.

...