2009-11-30 30 views
23

Quan sát mã nguồn đơn giản sau đây:Làm thế nào để phát ra thực hiện giao diện rõ ràng bằng cách sử dụng 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"); 
    } 
    } 
} 

Dưới đây là tương đương với C# code thu được bằng cách dịch ngược assembly A.dll sử dụng Reflector:

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

Bây giờ những gì nếu tôi muốn loại MyType thực hiện giao diện IMyInterface một cách rõ ràng? Vì vậy, tôi lấy những dòng này:

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

và chuyển đổi các ý kiến ​​để mang mã này:

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

Nhưng bây giờ, các ứng dụng không tạo ra các loại năng động. Dòng này:

var type = typeBuilder.CreateType(); 

ném ngoại lệ sau đây:

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: 

bất cứ ai có thể chỉ cho tôi những gì là sai với mã của tôi?

Cảm ơn.

Trả lời

28

Điều đó có vẻ trùng lặp để this question ...

nào points to MSDN:

Tuy nhiên, để cung cấp một riêng biệt thi hành IM(), bạn phải xác định nội dung phương pháp và sau đó sử dụng Phương pháp DefineMethodOverride để liên kết nội dung phương thức đó với MethodInfo đại diện cho IM(). Tên của nội dung phương thức không vấn đề.

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

Trên thực tế đó là, mặc dù tôi đã nhận thấy câu hỏi đó và thậm chí đã đến thăm các bài viết MSDN, nhưng sau khi đọc đoạn đầu tiên trong phần chú thích từ bỏ nó. Chỉ cần không nghĩ về việc thực hiện giao diện rõ ràng như đặt tên khác cho phương thức giao diện. Bây giờ tôi thấy sai lầm của tôi. Cảm ơn. – mark

+0

Đó là lý do tại sao việc xem xét mã hoạt động!) –

Các vấn đề liên quan