发出工厂方法
Emit a factory method
给定以下代码:
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 生成的代码位于此 post.
的末尾
我什至无法创建类型,出现此错误:
System.TypeLoadException : Signature of the body and declaration in a method implementation do not match.
我假设 class 定义/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)
对于 TestBar1Factory
,ILDASM 生成了这个。
CLASS 定义
.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);
return 类型必须是 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);
给定以下代码:
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 生成的代码位于此 post.
的末尾我什至无法创建类型,出现此错误:
System.TypeLoadException : Signature of the body and declaration in a method implementation do not match.
我假设 class 定义/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)
对于 TestBar1Factory
,ILDASM 生成了这个。
CLASS 定义
.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);
return 类型必须是 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);