可能重复:
为什么 C# 默认将方法实现为非虚拟方法?
我说的主要是 C#、.NET 3.5,但一般想知道不考虑所有“虚拟”的好处是什么——也就是说,在子类的实例中调用的方法总是执行最子版本那个方法。在 C# 中,如果父方法未使用“virtual”修饰符标记,则情况并非如此。例子:
public class Parent
{
public void NonVirtual() { Console.WriteLine("Non-Virtual Parent"); }
public virtual void Virtual(){ Console.WriteLine("Virtual Parent"); }
}
public class Child : Parent
{
public new void NonVirtual() { Console.WriteLine("Non-Virtual Child"); }
public override void Virtual() { Console.WriteLine("Virtual Child"); }
}
public class Program
{
public static void Main(string[] args)
{
Child child = new Child();
Parent parent = new Child();
var anon = new Child();
child.NonVirtual(); // => Child
parent.NonVirtual(); // => Parent
anon.NonVirtual(); // => Child
((Parent)child).NonVirtual(); // => Parent
child.Virtual(); // => Child
parent.Virtual(); // => Child
anon.Virtual(); // => Child
((Parent)child).Virtual(); // => Child
}
}
上面观察到的非虚拟行为究竟有什么好处?我唯一能想到的是“如果 Parent 的作者不希望他的方法是虚拟的怎么办?” 但后来我意识到我想不出一个好的用例。有人可能会争辩说,该类的行为取决于非虚拟方法的运行方式——但在我看来,这似乎是一些糟糕的封装,或者该方法应该被密封。
按照同样的思路,“隐藏”似乎通常是个坏主意。毕竟,如果创建了 Child 对象和方法,似乎是出于特定原因覆盖 Parent 的。而且,如果 Child 实现(并隐藏了父级)NonVirtual(),则很容易无法获得许多人可能认为的调用 Child::NonVirtual() 的“预期”行为。(我说“预期”是因为有时很容易不注意到“隐藏”正在发生)。
那么,不让一切都有“虚拟”行为有什么好处呢?如果很容易出现意外行为,那么隐藏非虚拟父级的好用例是什么?
如果有人好奇我为什么提出这个问题——我最近正在研究 Castle Projects DynamicProxy 库。使用它的一个主要障碍是您想要代理的任何方法(或属性)都必须是虚拟的。对于开发人员来说,这并不总是一种选择(如果我们无法控制源代码)。更不用说 DynamicProxy 的目的是避免代理类与您尝试使用代理实现的任何行为之间的耦合(例如 Logging,或者可能是 Memoization 实现)。并且通过强制虚拟方法来实现这一点,所实现的是 DynamicProxy 与它所代理的所有类的非常薄但钝的耦合 - 想象一下,您有大量标记为虚拟的方法,即使它们从未被继承和覆盖,
无论如何,那里的挫败感让我想知道非虚拟的好处是什么,当似乎让一切虚拟化可能更清楚(我想是 IMO)并且也许(?)有更多的好处。
编辑:标记为社区 wiki,因为这似乎是一个可能有主观答案的问题