发出覆盖非虚拟的方法

时间:2014-06-09 06:13:05

标签: .net dynamic override cil reflection.emit

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

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

要知道的第一件事是Sum方法不是虚拟的。我不想要这个限制 我想覆盖' Sum方法在运行时注入一些代码。 (就像任何动态代理框架一样./例如: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
  • CallingConventions
  • DefineMethodOverride方法

我的理念:明确制作方法PublicHideBySig。 vtable中的其他ReuseSlot,并使用ExplicitThis进行调用 知道怎么做到这一点?还是需要一些更讨厌的东西?
我知道外面有框架,但我想理解这个概念。

1 个答案:

答案 0 :(得分:2)

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

如果您尝试替换方法的行为(例如模拟对象时),则仍有一些选项。

远程处理

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

仿形

分析API允许在jit时进行检测。这允许您更改任何托管方法的行为,包括框架中的静态方法。这里的灵活性需要付出代价,实现需要花费更多的精力,并且需要使用特定的分析器来运行流程 - 如果您真的需要对代码进行分析,这是一个重大问题。

我在一个模拟库或其他模拟库中看到过这两种方法,我认为这两种方法都不适合生产代码。

相关问题