Given the following code:
public interface IBar1 { }
public class Bar1 : IBar1 { }
public interface IBar1Factory { IBar1 Factory(); }
I want to dynamically emit a type that looks like this.
public class TestBar1Factory : IBar1Factory
{
public IBar1 Factory() { return new Bar1(); }
}
Problem
I was following the tutorial here and I also created the type, manually built it and looked in ILDASM to emit the code exactly as it is inside the compiled DLL. The ILDASM generated code I'm trying to mimic is at the end of this post.
I cannot even create the type, I'm getting this error:
System.TypeLoadException : Signature of the body and declaration in a method implementation do not match.
I assume there is some problem with the enums inside the class definition / ctor / factory method? But I'm trying all sorts of combinations and the problem won't go away :(
My code
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();
Working IL code from ILDASM (from DLL compiled from Visual Studio)
For TestBar1Factory the ILDASM generates this.
CLASS DEFINITION
.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
FACTORY METHOD
.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
I see the following errors in your code. After fixing those I was able to run your without any problems.
The return type must be of typeof(IBar1). It is also a good practice to pass Type.EmptyTypes instead of null.
And in the following code, you have Stloc but it requires a target local variable.
Here is a quick fix