如何使用 Reflection.emit 发出显式接口实现?

发布于 2024-08-13 04:29:31 字数 3853 浏览 6 评论 0原文

请观察以下简单的源代码:

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

下面是通过使用 Reflector 反编译 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: 

任何人都可以告诉我我的代码有什么问题吗?

谢谢。

Observe the following simple source code:

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

Below is the equivalent C# code obtained by decompiling the A.dll assembly using the Reflector:

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

Now what if I wish the MyType type implement the IMyInterface interface explicitly?
So I take these lines:

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

and switch the comments to yield this code:

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

But now, the application fails to create the dynamic type. This line:

var type = typeBuilder.CreateType();

throws the following exception:

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: 

Can anyone show me what is wrong with my code?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不必在意 2024-08-20 04:29:31

这似乎与这个问题重复......

哪个指向 MSDN

但是,要提供单独的
实现 IM() 时,您必须
定义一个方法体,然后使用
DefineMethodOverride 方法
将该方法体与
MethodInfo 代表 IM()。这
方法体的名称不
事情。

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

That seems duplicate to this question...

Which points to MSDN:

However, to provide a separate
implementation of I.M(), you must
define a method body and then use the
DefineMethodOverride method to
associate that method body with a
MethodInfo representing I.M(). The
name of the method body does not
matter.

        // 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"));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文