Effective C# Item29: Use the new Modifier Only When Base Class Updates Mandate it
当我们需要重定义一个基类中非虚的成员时,我们可以使用new修饰符,但这并不意味着我们应该这样做。这种重定义会引起行为上的歧义。大部分程序员看到下面的两端代码时都会认为如果这两个类是继承关系的话,它们的行为应该时相同的:
object c = MakeObject();
MyClass c1 = c as MyClass;
c1.MagicMethod();
MyOtherClass c2 = c as MyOtherClass;
c2.MagicMethod();但是如果通过new进行重定义,那么结果可能并不是这样:
public class MyClass
{
public void MagicMethod()
{
}
}
public class MyOtherClass : MyClass
{
public new void MagicMethod()
{
}
}像这种情况经常会让很多开发人员头疼。如果调用同一个对象的同一个方法,我们期望执行结果是相同的。但是事实上虽然名称相同,但它们调用的函数却是完全不同的,这非常糟糕。它破坏了唯一性。MyOtherClass对象的行为并不是我们期望的。使用new修饰符可以让我们在类中添加一个完全不同的方法,这不同于重写基类中的虚方法。
非虚的方法都是静态确定的。不论在任何位置的代码,这些方法都调用同样的函数。在运行时不会在其派生类中寻找此方法的不同版本。而虚方法是动态确定的。运行时将通过不同的类型来调用该方法不同的版本。
我们应当避免使用new来重定义非虚方法。不然我们就需要将基类中的所有方法都声明为虚的。设计者通过定义这些虚方法为类添加了一种行为约定。它的派生类都可以通过这个虚方法来达到自己不同的实现需要。每一条虚方法都定义了其派生类可能需要改变的行为。“默认虚方法”的设计认为基类中所有的方法都为虚,派生类可以修改基类中所有的行为。这往往意味着你并没有认真思考派生类之间行为的分支关系。我们应当多花些时间思考派生类中哪些方法和属性时需要多态性的,仅仅把这些有需要的方法和属性设为虚的。我们不要将这想象为对用户的限制。而是将它看作指导用户自定义行为的入口。
