Как использовать отражение .NET для создания универсальных интерфейсов и класса, который их реализуетC#

Место общения программистов C#
Ответить
Anonymous
 Как использовать отражение .NET для создания универсальных интерфейсов и класса, который их реализует

Сообщение Anonymous »

Я пытаюсь использовать отражение .NET для создания класса и некоторых интерфейсов, которые этот класс реализует. Однако я не могу правильно реализовать универсальные интерфейсы, поскольку это приводит к ошибкам при создании типа класса.
Приведенный ниже код должен генерировать классы и интерфейсы, эквивалентные следующему C#

Код: Выделить всё

public interface MyInterface1
{
void IfaceMethod(int arg);
}

public interface MyInterface2
{
void IfaceMethod(int arg);
}

public interface MyInterface3
{
void IfaceMethod(T arg);
}

public class MyClass : MyInterface1, MyInterface2, MyInterface3
{
void MyInterface1.IfaceMethod(int arg)
{
Console.WriteLine(...);
}

void MyInterface2.IfaceMethod(int arg)
{
Console.WriteLine(...);
}

void MyInterface3.IfaceMethod(int arg)
{
Console.WriteLine(...);
}
}
Мой код, использующий отражение для создания этого:

Код: Выделить всё

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 and MyInterface3 */
List interfaces = new List();
// 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 methods = new List();
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);
}
}
}
Я получаю сообщения об ошибках при вызове class_builder.CreateType(), если не закомментирую строки Interfaces.Add(...), которые добавляют мои общие интерфейсы (interface2 и интерфейс3) в список.
При попытке реализовать MyInterface2 появляется сообщение об ошибке

Код: Выделить всё

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
и когда я пытаюсь реализовать MyInterface3, возникает ошибка

Код: Выделить всё

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
Я ожидаю, что все реализации интерфейса будут работать, поскольку все сигнатуры методов интерфейса эквивалентны, учитывая конкретные аргументы типа, применяемые к моим универсальным интерфейсам.
Любые намеки на то, чего мне здесь не хватает, будут оценены по достоинству. Я пробовал это, используя как .NET 8.0, так и .NET 9.0, разницы нет.

Подробнее здесь: https://stackoverflow.com/questions/798 ... ich-implem
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»