2009-11-30 3 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に関連付けられます。メソッド本体の の名前は ではありません。私はその質問に気づきましたとも、MSDNの記事を訪問したが、備考セクションの最初の段落を読んだ後、それを放棄したものの

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

は確かにそれは、あります。明示的なインタフェースの実装は、インタフェースのメソッドに別の名前を付けるとは考えていませんでした。今私は間違いを見る。ありがとう。 – mark

+0

そのため、コードレビューが機能します。 ) –

関連する問題