所以我在程序集中有一个简单的类驻留:
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
DefineMethodOverride
方法我的理念:明确制作方法Public
并HideBySig
。 vtable中的其他ReuseSlot
,并使用ExplicitThis
进行调用
知道怎么做到这一点?还是需要一些更讨厌的东西?
我知道外面有框架,但我想理解这个概念。
答案 0 :(得分:2)
如果您特别想要覆盖该方法,那么正如svick在评论中所说,您的运气不好。原因是如果该方法在IL中没有标记为虚拟(这与C#中的虚拟稍有不同),那么它将不会在虚方法表中给出一个槽,因此子类无法覆盖它。有时C#会将非虚拟方法编译为IL中的虚拟和最终方法但如果您尝试覆盖最终方法,那么它将无法将验证作为安全风险。
如果您尝试替换方法的行为(例如模拟对象时),则仍有一些选项。
如果对象恰好从MarshalByRefObject继承,那么您可以使用远程处理系统来模拟对象。基本上,告诉CLR该对象存在于其他地方,并且您将代表它们编组消息。这种方法允许您模拟非虚拟实例方法,只要它们是在继承自MarshalByRefObject的对象上定义的,并从对象外部调用。
分析API允许在jit时进行检测。这允许您更改任何托管方法的行为,包括框架中的静态方法。这里的灵活性需要付出代价,实现需要花费更多的精力,并且需要使用特定的分析器来运行流程 - 如果您真的需要对代码进行分析,这是一个重大问题。
我在一个模拟库或其他模拟库中看到过这两种方法,我认为这两种方法都不适合生产代码。