c# .net reflection reflection.emit explicit-implementation

c# - ¿Cómo emitir una implementación de interfaz explícita usando reflection.emit?



.net explicit-implementation (1)

Observe el siguiente código fuente simple:

using System; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; namespace A { public static class Program { private const MethodAttributes ExplicitImplementation = MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot; private const MethodAttributes ImplicitImplementation = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig; private static Type EmitMyIntfType(ModuleBuilder moduleBuilder) { var typeBuilder = moduleBuilder.DefineType("IMyInterface", TypeAttributes.NotPublic | TypeAttributes.Interface | TypeAttributes.Abstract); typeBuilder.DefineMethod("MyMethod", MethodAttributes.Assembly | MethodAttributes.Abstract | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot, typeof(void), new[] { typeof(int) }); return typeBuilder.CreateType(); } public static void Main() { var assemblyName = new AssemblyName("DynamicTypesAssembly"); var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll", true); var myIntfType = EmitMyIntfType(moduleBuilder); var typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public | TypeAttributes.BeforeFieldInit | TypeAttributes.Serializable | TypeAttributes.Sealed, typeof(object), new[] { myIntfType }); //var myMethodImpl = typeBuilder.DefineMethod("IMyInterface.MyMethod", ExplicitImplementation, // null, new[] { typeof(int) }); var myMethodImpl = typeBuilder.DefineMethod("MyMethod", ImplicitImplementation, null, new[] { typeof(int) }); var ilGenerator = myMethodImpl.GetILGenerator(); ilGenerator.Emit(OpCodes.Ret); var type = typeBuilder.CreateType(); assemblyBuilder.Save("A.dll"); } } }

A continuación se muestra el código C # equivalente obtenido al descompilar el ensamblaje A.dll utilizando el Reflector:

internal interface IMyInterface { void MyMethod(int); } [Serializable] public sealed class MyType : IMyInterface { public override void MyMethod(int) { } }

Ahora, ¿qué MyType si deseo que el tipo MyType implemente explícitamente la interfaz IMyInterface ? Así que tomo estas líneas:

//var myMethodImpl = typeBuilder.DefineMethod("IMyInterface.MyMethod", ExplicitImplementation, // null, new[] { typeof(int) }); var myMethodImpl = typeBuilder.DefineMethod("MyMethod", ImplicitImplementation, null, new[] { typeof(int) });

y cambia los comentarios para producir este código:

var myMethodImpl = typeBuilder.DefineMethod("IMyInterface.MyMethod", ExplicitImplementation, null, new[] { typeof(int) }); // var myMethodImpl = typeBuilder.DefineMethod("MyMethod", ImplicitImplementation, // null, new[] { typeof(int) });

Pero ahora, la aplicación no logra crear el tipo dinámico. Esta línea:

var type = typeBuilder.CreateType();

lanza la siguiente excepción:

System.TypeLoadException was unhandled Message="Method ''MyMethod'' in type ''MyType'' from assembly ''DynamicTypesAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'' does not have an implementation." Source="mscorlib" TypeName="MyType" StackTrace: at System.Reflection.Emit.TypeBuilder._TermCreateClass(Int32 handle, Module module) at System.Reflection.Emit.TypeBuilder.TermCreateClass(Int32 handle, Module module) at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock() at System.Reflection.Emit.TypeBuilder.CreateType() at A.Program.Main() in C:/Home/work/A/Program.cs:line 45 InnerException:

¿Alguien puede mostrarme lo que está mal con mi código?

Gracias.


Eso parece duplicado a esta pregunta ...

Lo que apunta a MSDN :

Sin embargo, para proporcionar una implementación separada de IM (), debe definir un cuerpo de método y luego usar el método DefineMethodOverride para asociar ese cuerpo de método con un MethodInfo representa a IM (). El nombre del cuerpo del método no importa.

// Build the method body for the explicit interface // implementation. The name used for the method body // can be anything. Here, it is the name of the method, // qualified by the interface name. // MethodBuilder mbIM = tb.DefineMethod("I.M", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, null, Type.EmptyTypes); ILGenerator il = mbIM.GetILGenerator(); il.Emit(OpCodes.Ldstr, "The I.M implementation of C"); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); il.Emit(OpCodes.Ret); // DefineMethodOverride is used to associate the method // body with the interface method that is being implemented. // tb.DefineMethodOverride(mbIM, typeof(I).GetMethod("M"));