2009-11-30 17 views
23

osservare il seguente codice sorgente semplice:Come emettere un'implementazione esplicita dell'interfaccia usando reflection.emit?

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

Di seguito si riporta il codice equivalente C# ottenuto dalla decompilazione l'assemblaggio A.dll utilizzando il riflettore:

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

Ora che cosa se voglio il tipo MyType implementare l'interfaccia IMyInterface esplicitamente? Così prendo queste righe:

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

e passare i commenti a cedere questo codice:

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

Ma ora, l'applicazione non riesce a creare il tipo dinamico. Questa linea:

var type = typeBuilder.CreateType(); 

getta la seguente eccezione:

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: 

Qualcuno mi può mostrare ciò che è sbagliato con il mio codice?

Grazie.

risposta

28

che sembra duplicare a this question ...

Quali points to MSDN:

Tuttavia, per fornire un implementazione separata di IM(), è necessario definire un corpo del metodo e quindi utilizzare il Metodo DefineMethodOverride su associare il corpo del metodo a MethodInfo che rappresenta IM(). Il nome del corpo del metodo non corrisponde a .

 // 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")); 
+0

infatti lo è, anche se ho notato che domanda e anche visitato l'articolo di MSDN, ma dopo aver letto il primo paragrafo nella sezione Osservazioni abbandonata. Semplicemente non pensavo all'implementazione esplicita dell'interfaccia come dare un altro nome al metodo dell'interfaccia. Ora vedo il mio errore. Grazie. – mark

+0

Ecco perché la revisione del codice funziona!) –

Problemi correlati