I am trying to use .NET reflection to emit a class and some interfaces which the class implements. However, I cannot seem to correctly implement the interfaces that are generic, as that results in errors when the class type is created.
The code below is supposed to emit classes and interfaces equivalent to the following C#
public interface MyInterface1
{
void IfaceMethod(int arg);
}
public interface MyInterface2<T>
{
void IfaceMethod(int arg);
}
public interface MyInterface3<T>
{
void IfaceMethod(T arg);
}
public class MyClass : MyInterface1, MyInterface2<double>, MyInterface3<int>
{
void MyInterface1.IfaceMethod(int arg)
{
Console.WriteLine(...);
}
void MyInterface2<double>.IfaceMethod(int arg)
{
Console.WriteLine(...);
}
void MyInterface3<int>.IfaceMethod(int arg)
{
Console.WriteLine(...);
}
}
My code using reflection to emit this is
using System.Reflection;
using System.Reflection.Emit;
class Test
{
static void Main()
{
string example_name = "Interface example";
AssemblyName asm_name = new AssemblyName(example_name);
AssemblyBuilder asm_builder = AssemblyBuilder.DefineDynamicAssembly(asm_name, AssemblyBuilderAccess.Run);
ModuleBuilder module_builder = asm_builder.DefineDynamicModule(example_name);
TypeBuilder class_builder = module_builder.DefineType("MyClass", TypeAttributes.Public | TypeAttributes.Class);
TypeBuilder interface1_builder = module_builder.DefineType("MyInterface1", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
TypeBuilder interface2_builder = module_builder.DefineType("MyInterface2", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
TypeBuilder interface3_builder = module_builder.DefineType("MyInterface3", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
Type[] interface2_generics = interface2_builder.DefineGenericParameters(["T"]);
Type[] interface3_generics = interface3_builder.DefineGenericParameters(["T"]);
MethodAttributes method_attributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract;
interface1_builder.DefineMethod("IfaceMethod", method_attributes, null, [typeof(int)]);
interface2_builder.DefineMethod("IfaceMethod", method_attributes, null, [typeof(int)]);
interface3_builder.DefineMethod("IfaceMethod", method_attributes, null, interface3_generics);
Type interface1_type = interface1_builder.CreateType();
Type interface2_type = interface2_builder.CreateType();
Type interface3_type = interface3_builder.CreateType();
/* Now let MyClass implement IfaceMethod from MyInterface1, MyInterface2<double> and MyInterface3<int> */
List<Type> interfaces = new List<Type>();
// Interface1 always works
interfaces.Add(interface1_type);
// Interface2 errors with: Unhandled exception. System.TypeLoadException: Type 'MyClass' from assembly
// 'Interface example, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' tried to override
// method 'fn_0' but does not implement or inherit that method.
interfaces.Add(interface2_type.MakeGenericType([typeof(double)]));
// Interface3 errors with: Unhandled exception. System.TypeLoadException: Signature of the body and
// declaration in a method implementation do not match. Type: 'MyClass'. Assembly:
// 'Interface example, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
interfaces.Add(interface3_type.MakeGenericType([typeof(int)]));
List<MethodInfo> methods = new List<MethodInfo>();
for(int i = 0; i < interfaces.Count; i++){
Type interface_type = interfaces[i];
class_builder.AddInterfaceImplementation(interface_type);
string method_name = "fn_"+i;
MethodBuilder class_method = class_builder.DefineMethod(method_name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, null, [typeof(int)]);
ILGenerator il = class_method.GetILGenerator();
il.EmitWriteLine("Hello from " + method_name + " implementing IfaceMethod from " + interface_type.Name);
il.Emit(OpCodes.Ret);
MethodInfo interface_method = interface_type.GetMethod("IfaceMethod");
class_builder.DefineMethodOverride(class_method, interface_method);
methods.Add(interface_method);
}
Type class_type = class_builder.CreateType();
object obj = Activator.CreateInstance(class_type);
Object[] args = [123];
foreach(MethodInfo method in methods){
method.Invoke(obj, args);
}
}
}
I get error messages from the class_builder.CreateType() call, unless I comment out the interfaces.Add(...) lines that adds my generic interfaces (interface2 and interface3) to the list.
The error message when I attempt to implement MyInterface2 is
Unhandled exception. System.TypeLoadException: Type 'MyClass' from
assembly 'Interface example, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null' tried to override method 'fn_0' but does not
implement or inherit that method.
at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeInfoImpl()
at Test.Main() in C:\tmp\interface-issue\Program.cs:line 62
and when I attempt to implement MyInterface3 the error is
Unhandled exception. System.TypeLoadException: Signature of the body
and declaration in a method implementation do not match.
Type: 'MyClass'. Assembly: 'Interface example, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.RuntimeTypeBuilder.CreateTypeInfoImpl()
at Test.Main() in C:\tmp\interface-issue\Program.cs:line 62
I would expect all the interface implementations to work, since the interface method signatures are all equivalent given the concrete type arguments applied to my generic interfaces.
Any hints at what I am missing here would be appreciated. I have tried this using both .NET 8.0 and .NET 9.0, and there is no difference.
Edit: fixed version based on the accepted solution below.
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Linq;
class Test
{
static void Main()
{
string example_name = "Interface example";
AssemblyName asm_name = new AssemblyName(example_name);
AssemblyBuilder asm_builder = AssemblyBuilder.DefineDynamicAssembly(asm_name, AssemblyBuilderAccess.Run);
ModuleBuilder module_builder = asm_builder.DefineDynamicModule(example_name);
TypeBuilder class_builder = module_builder.DefineType("MyClass", TypeAttributes.Public | TypeAttributes.Class);
TypeBuilder interface1_builder = module_builder.DefineType("MyInterface1", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
TypeBuilder interface2_builder = module_builder.DefineType("MyInterface2", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
TypeBuilder interface3_builder = module_builder.DefineType("MyInterface3", TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
Type[] interface2_generics = interface2_builder.DefineGenericParameters(["T"]);
Type[] interface3_generics = interface3_builder.DefineGenericParameters(["T"]);
MethodAttributes method_attributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract;
List<MethodBuilder> interface_method_builders = new List<MethodBuilder>();
interface_method_builders.Add(interface1_builder.DefineMethod("IfaceMethod", method_attributes, null, [typeof(int)]));
interface_method_builders.Add(interface2_builder.DefineMethod("IfaceMethod", method_attributes, null, [typeof(int)]));
interface_method_builders.Add(interface3_builder.DefineMethod("IfaceMethod", method_attributes, null, interface3_generics));
interface1_builder.CreateType();
interface2_builder.CreateType();
interface3_builder.CreateType();
List<Type> interfaces = new List<Type>();
interfaces.Add(interface1_builder);
interfaces.Add(interface2_builder.MakeGenericType([typeof(double)]));
interfaces.Add(interface3_builder.MakeGenericType([typeof(int)]));
for(int i = 0; i < interfaces.Count; i++){
Type interface_type = interfaces[i];
MethodInfo interface_method = interface_method_builders[i];
try
{
interface_method = TypeBuilder.GetMethod(interface_type, interface_method); /* in case it was from a generic interface*/
}
catch(Exception)
{
}
class_builder.AddInterfaceImplementation(interface_type);
string method_name = "fn_"+i;
MethodBuilder class_method = class_builder.DefineMethod(method_name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, null, [typeof(int)]);
ILGenerator il = class_method.GetILGenerator();
il.EmitWriteLine("Hello from " + method_name + " implementing IfaceMethod from " + interface_type.Name);
il.Emit(OpCodes.Ret);
class_builder.DefineMethodOverride(class_method, interface_method);
}
Type class_type = class_builder.CreateType();
object obj = Activator.CreateInstance(class_type);
List<MethodInfo> methods = class_type.GetInterfaces().Select(i => i.GetMethod("IfaceMethod")).ToList();
Object[] args = [123];
foreach(MethodInfo method in methods){
method.Invoke(obj, args);
}
}
}