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 unMethodInfo
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"));