2009-11-30 48 views
23

遵守以下簡單的源代碼:如何使用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"); 
    } 
    } 
} 

以下是使用反射器由反編譯獲得的A.DLL裝配等效C#代碼:

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

現在,如果我希望MyType類型實施明確界面IMyInterface? 所以我把這些線:

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

和切換的意見,得到這個代碼:

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

但現在,應用程序無法創建動態類型。這條線:

var type = typeBuilder.CreateType(); 

拋出以下異常:

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: 

誰能告訴我什麼是錯我的代碼?

謝謝。

回答

28

這似乎複製到this question ......

其中points to MSDN

但是,爲了提供一個單獨的 實現IM(),您必須 定義方法體,然後使用 DefineMethodOverride方法到 將該方法主體與表示IM()的 MethodInfo相關聯。方法體的名稱 不是 的問題。

 // 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

確實是這樣,但我也注意到了這個問題,甚至訪問MSDN文章,但閱讀備註部分的第一段後放棄了它。只是沒有將顯式接口實現視爲給接口方法另外命名。現在我看到了我的錯誤。謝謝。 – mark

+0

這就是爲什麼代碼審查的作品! ) –