如何使用 Mono.Cecil 为接口方法实现别名?

发布于 2024-09-10 02:00:54 字数 2417 浏览 1 评论 0原文

我使用 Mono.Cecil (版本 0.6.9.0)为实现接口方法的方法添加别名。为此,我必须向目标方法添加一个 Override 来指向接口方法(很像 VB.NET 的情况),如下所示:

using System;
using System.Reflection;
using Mono.Cecil;

class Program {

  static void Main(string[] args) {
    var asm = AssemblyFactory.GetAssembly(Assembly.GetExecutingAssembly().Location);

    var source = asm.MainModule.Types["A"];
    var sourceMethod = source.Methods[0];
    var sourceRef = new MethodReference(
      sourceMethod.Name,
      sourceMethod.DeclaringType,
      sourceMethod.ReturnType.ReturnType,
      sourceMethod.HasThis,
      sourceMethod.ExplicitThis,
      sourceMethod.CallingConvention);

    var target = asm.MainModule.Types["C"];
    var targetMethod = target.Methods[0];
    targetMethod.Name = "AliasedMethod";
    targetMethod.Overrides.Add(sourceRef);

    AssemblyAssert.Verify(asm); // this will just run PEVerify on the changed assembly
  }

}

interface A {
  void Method();
}

class C : A {
  public void Method() { }
}

我得到的是一个 < code>PEVerify.exe 错误,表明我的类不再实现接口方法。似乎在更改的程序集中重写引用和接口中的方法之间存在标记不匹配:

[MD]: Error: Class implements interface but not method (class:0x02000004; interface:0x02000002; method:0x06000001). [token:0x09000001]

我知道如果我直接使用 MethodDefinition 它将起作用:

targetMethod.Overrides.Add(sourceMethod);

但我确实需要使用 < code>MethodReference 因为我可能在所涉及的类型中具有通用参数和实参,而简单的 MethodDefinition 是不行的。

更新:按照Jb Evain,我已经迁移到版本 0.9 .3.0。但是,同样的错误仍然发生。这是迁移后的代码:

var module = ModuleDefinition.ReadModule(Assembly.GetExecutingAssembly().Location);

var source = module.GetType("A");
var sourceMethod = source.Methods[0];

var sourceRef = new MethodReference(
  sourceMethod.Name,
  sourceMethod.ReturnType) {
    DeclaringType = sourceMethod.DeclaringType,
    HasThis = sourceMethod.HasThis,
    ExplicitThis = sourceMethod.ExplicitThis,
    CallingConvention = sourceMethod.CallingConvention 
};

var target = module.GetType("C");
var targetMethod = target.Methods[0];
targetMethod.Name = "AliasedMethod";
targetMethod.Overrides.Add(sourceRef);

I'm using Mono.Cecil (version 0.6.9.0) to alias a method that implements an interface method. To do that, I have to add an Override to the target method that points back to the interface method (much like what's possible with VB.NET), like this:

using System;
using System.Reflection;
using Mono.Cecil;

class Program {

  static void Main(string[] args) {
    var asm = AssemblyFactory.GetAssembly(Assembly.GetExecutingAssembly().Location);

    var source = asm.MainModule.Types["A"];
    var sourceMethod = source.Methods[0];
    var sourceRef = new MethodReference(
      sourceMethod.Name,
      sourceMethod.DeclaringType,
      sourceMethod.ReturnType.ReturnType,
      sourceMethod.HasThis,
      sourceMethod.ExplicitThis,
      sourceMethod.CallingConvention);

    var target = asm.MainModule.Types["C"];
    var targetMethod = target.Methods[0];
    targetMethod.Name = "AliasedMethod";
    targetMethod.Overrides.Add(sourceRef);

    AssemblyAssert.Verify(asm); // this will just run PEVerify on the changed assembly
  }

}

interface A {
  void Method();
}

class C : A {
  public void Method() { }
}

What I'm getting is a PEVerify.exe error that indicates that my class doesn't implement the interface method anymore. It seems that there's a token mismatch in the changed assembly between the override reference and the method in the interface:

[MD]: Error: Class implements interface but not method (class:0x02000004; interface:0x02000002; method:0x06000001). [token:0x09000001]

I know that if I use the MethodDefinition directly it will work:

targetMethod.Overrides.Add(sourceMethod);

But I really need to use a MethodReference because I might have generic parameters and arguments in the types involved, and a simple MethodDefinition won't do.

Update: As recommended by Jb Evain, I've migrated to version 0.9.3.0. But, the same error still happens. Here's the migrated code:

var module = ModuleDefinition.ReadModule(Assembly.GetExecutingAssembly().Location);

var source = module.GetType("A");
var sourceMethod = source.Methods[0];

var sourceRef = new MethodReference(
  sourceMethod.Name,
  sourceMethod.ReturnType) {
    DeclaringType = sourceMethod.DeclaringType,
    HasThis = sourceMethod.HasThis,
    ExplicitThis = sourceMethod.ExplicitThis,
    CallingConvention = sourceMethod.CallingConvention 
};

var target = module.GetType("C");
var targetMethod = target.Methods[0];
targetMethod.Name = "AliasedMethod";
targetMethod.Overrides.Add(sourceRef);

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

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

发布评论

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

评论(1

不…忘初心 2024-09-17 02:00:54

这是使用 0.6 的烦恼之一。您必须将新创建的 MethodReference 放入模块的 .MemberReferences 集合中。

我强烈建议你切换到0.9。

That's one of the annoyance of using the 0.6. You have to put the newly created MethodReference in the .MemberReferences collection of your module.

I strongly suggest you switch to 0.9.

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