问题描述
给出以下代码:
public interface IBar1 { }
public class Bar1 : IBar1 { }
public interface IBar1Factory { IBar1 Factory(); }
我想动态地发出看起来像这样的类型。
public class TestBar1Factory : IBar1Factory
{
public IBar1 Factory() { return new Bar1(); }
}
问题
我遵循tutorial here,并且我还创建了该类型,手动构建了该类型,并查看了ILDASM以发出与已编译DLL内的代码完全相同的代码。我要模仿的ILDASM生成的代码在本文的结尾。
我什至无法创建类型,但出现此错误:
System.TypeLoadException : Signature of the body and declaration in a method implementation do not match.
我认为类定义/ ctor /工厂方法中的枚举有问题吗?但我正在尝试各种组合,问题不会消失:(
我的代码
AssemblyName asmName = new AssemblyName { Name = "ToFactoryDynamicAssembly" };
AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName,AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule("ToFactoryModule");
ConstructorInfo systemObjectCtor = Type.GetType("System.Object").GetConstructor(new Type[0]);
TypeBuilder facBuilder = moduleBuilder.DefineType($"DynamicFactoryFor{typeof(IBar1Factory).Name}",TypeAttributes.Public
| TypeAttributes.AutoClass
| TypeAttributes.AnsiClass
| TypeAttributes.BeforeFieldInit);
facBuilder.AddInterfaceImplementation(typeof(IBar1Factory));
ConstructorBuilder facCtorBuilder = facBuilder.DefineConstructor(MethodAttributes.Public
| MethodAttributes.HideBySig
| MethodAttributes.SpecialName
| MethodAttributes.RTSpecialName,CallingConventions.Standard,null);
var ctorIL = facCtorBuilder.GetILGenerator();
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Call,systemObjectCtor);
ctorIL.Emit(OpCodes.nop);
ctorIL.Emit(OpCodes.Ret);
var methodBuilder = facBuilder.DefineMethod("Factory",MethodAttributes.Public
| MethodAttributes.HideBySig
| MethodAttributes.NewSlot
| MethodAttributes.Virtual
| MethodAttributes.Final,typeof(IBar),null);
var bar1Ctor = typeof(Bar1).GetConstructors()[0];
var methodIL = methodBuilder.GetILGenerator();
methodIL.Emit(OpCodes.nop);
methodIL.Emit(OpCodes.Newobj,bar1Ctor);
methodIL.Emit(OpCodes.Stloc_0);
methodIL.Emit(OpCodes.Ldloc_0);
methodIL.Emit(OpCodes.Ret);
facBuilder.DefineMethodoverride(methodBuilder,typeof(IBar1Factory).getmethod("Factory"));
var type = facBuilder.CreateType(); // error
var ctor = type.GetConstructors()[0];
IBar1Factory factory = ctor.Invoke(null) as IBar1Factory;
IBar1 bar1 = factory.Factory();
来自ILDASM的有效IL代码(来自Visual Studio编译的DLL)
类别定义
.class public auto ansi beforefieldinit AddFactoryExtension.Tests.TestBar1Factory
extends [System.Runtime]System.Object
implements AddFactoryExtension.Tests.IBar1Factory
{
} // end of class AddFactoryExtension.Tests.TestBar1Factory
CTOR
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TestBar1Factory::.ctor
工厂方法
.method public hidebysig newslot virtual final
instance class AddFactoryExtension.Tests.IBar1
Factory() cil managed
{
// Code size 11 (0xb)
.maxstack 1
.locals init (class AddFactoryExtension.Tests.IBar1 V_0)
IL_0000: nop
IL_0001: newobj instance void AddFactoryExtension.Tests.Bar1::.ctor()
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret
} // end of method TestBar1Factory::Factory
解决方法
我在您的代码中看到以下错误。修复这些问题后,我可以毫无问题地运行您的计算机。
var methodBuilder = facBuilder.DefineMethod("Factory",...,typeof(IBar),null);
返回类型必须为typeof(IBar1)。传递Type.EmptyTypes而不是null也是一个好习惯。
在下面的代码中,您拥有Stloc,但它需要一个目标局部变量。
var methodIL = methodBuilder.GetILGenerator();
methodIL.Emit(OpCodes.Nop);
methodIL.Emit(OpCodes.Newobj,bar1Ctor);
methodIL.Emit(OpCodes.Stloc_0);
methodIL.Emit(OpCodes.Ldloc_0);
这是一个快速解决方法
var bar1Ctor = typeof(Bar1).GetConstructors()[0];
var methodIL = methodBuilder.GetILGenerator();
methodIL.Emit(OpCodes.Newobj,bar1Ctor);
methodIL.Emit(OpCodes.Ret);