.net - 发出方法来覆盖非虚拟对象

标签 .net dynamic overriding cil reflection.emit

所以我的程序集中有一个简单的类:

public class MyCalculator
  {
    public int Sum(params int[] nums)
    {
      Console.WriteLine("Summing");
      return nums.Sum();
    }
  }

首先要知道的是 Sum 方法不是虚拟的。我不想要这个限制。
我想“覆盖” Sum 方法以在运行时注入(inject)一些代码。 (就像任何动态代理框架一样。/例如:CaSTLe/)
我创建了一个虚拟方法(仅相关部分):

MethodBuilder sumBuilder = myCalculatorProxyType.DefineMethod(myCalculatorSum.Name,
        MethodAttributes.Public |
        MethodAttributes.ReuseSlot |
        MethodAttributes.HideBySig |
        MethodAttributes.SpecialName |
        MethodAttributes.Virtual |
        MethodAttributes.Final,
        CallingConventions.Standard, 
        myCalculatorSum.ReturnType, 
        myCalculatorSum.GetParameters().Select(pi => pi.ParameterType).ToArray());

最后我尝试用以下方法“覆盖”它:

myCalculatorProxyType.DefineMethodOverride(sumBuilder,myCalculatorSum);

我玩了三个可能的选项:

  • MethodAttributes
  • 调用约定
  • 以及DefineMethodOverride方法

我的想法:使方法明显PublicHideBySig。在 vtable 中附加 ReuseSlot 并使用 ExplicitThis 调用它。
知道如何实现这一目标吗?或者需要一些更讨厌的东西?
我知道外面有框架,但我想了解这个概念。

最佳答案

如果您特别想重写该方法,那么正如 svick 在评论中所说,您运气不好。原因是,如果该方法在 IL 中没有标记为虚拟(这与 C# 中的虚拟有点不同),那么它不会在虚拟方法表中获得一个槽位,因此子类无法重写它。有时,C# 会将非虚拟方法编译为 IL 中的虚拟方法和 final方法,但如果您尝试覆盖 final方法,那么它将因安全风险而无法通过验证。

如果您尝试替换方法的行为(例如在模拟对象时),那么仍然有一些潜在的选择。

远程处理

如果该对象碰巧继承自 MarshalByRefObject,那么您可以使用远程处理系统来模拟该对象。本质上,告诉 CLR 该对象存在于其他地方,并且您将代表它编码(marshal)消息。这种方法将允许您模拟非虚拟实例方法,只要它们是在继承自 MarshalByRefObject 的对象上定义并从该对象外部调用即可。

分析

分析 API 允许在即时运行时进行检测。这允许您更改任何托管方法的行为,包括框架中的静态方法。不过,这里的灵活性是有代价的,它需要花费更多的精力来实现,并且需要使用特定的分析器来运行该过程 - 如果您确实需要分析您的代码,那么这是一个严重的问题。

我已经看到这两种方法在一个或另一个模拟库中使用,我认为这两种方法都不适合生产代码。

关于.net - 发出方法来覆盖非虚拟对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24114592/

相关文章:

c++ - 用于分析 bool vector 的 vector 的动态规划

c# - 契约(Contract)的不同属性(property)值(value)

c# - 带有用于服务器端渲染的 Javascript View 引擎的 Asp.Net MVC - 服务器上的构建错误

python - 如何连接对象以在 Python 中创建或调用变量? - 编辑

java - 使用第 1、2 或 3 步计算到达第 4 个楼梯的方式

google-chrome - Google Chrome - 覆盖网页加载之间的白色空白页

.net - OWIN 身份验证管道正确使用 Katana 中间件?

c# - 异步组件和 WinForms

c - 尝试覆盖 'fopen()' 但 GCC 给出 "error: conflicting types for ' fopen'"

java - 如何访问子类中抽象类的重写的非静态方法