所以我的程序集中有一个简单的类:
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
方法
我的想法:使方法明显Public
并HideBySig
。在 vtable 中附加 ReuseSlot
并使用 ExplicitThis
调用它。
知道如何实现这一目标吗?或者需要一些更讨厌的东西?
我知道外面有框架,但我想了解这个概念。
最佳答案
如果您特别想重写该方法,那么正如 svick 在评论中所说,您运气不好。原因是,如果该方法在 IL 中没有标记为虚拟(这与 C# 中的虚拟有点不同),那么它不会在虚拟方法表中获得一个槽位,因此子类无法重写它。有时,C# 会将非虚拟方法编译为 IL 中的虚拟方法和 final方法,但如果您尝试覆盖 final方法,那么它将因安全风险而无法通过验证。
如果您尝试替换方法的行为(例如在模拟对象时),那么仍然有一些潜在的选择。
远程处理
如果该对象碰巧继承自 MarshalByRefObject,那么您可以使用远程处理系统来模拟该对象。本质上,告诉 CLR 该对象存在于其他地方,并且您将代表它编码(marshal)消息。这种方法将允许您模拟非虚拟实例方法,只要它们是在继承自 MarshalByRefObject 的对象上定义并从该对象外部调用即可。
分析
分析 API 允许在即时运行时进行检测。这允许您更改任何托管方法的行为,包括框架中的静态方法。不过,这里的灵活性是有代价的,它需要花费更多的精力来实现,并且需要使用特定的分析器来运行该过程 - 如果您确实需要分析您的代码,那么这是一个严重的问题。
我已经看到这两种方法在一个或另一个模拟库中使用,我认为这两种方法都不适合生产代码。
关于.net - 发出方法来覆盖非虚拟对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24114592/