几乎 .NET 所有开发人员都知道 new 修饰符可以重新定义从基类中继承的非虚成员,但是大部分开发人员并不知道怎么才能正确使用,甚至出现了滥用的情况。
零、纠正常犯错误
讲解如何正确使用 new 修饰符前我们先来看一个段代码。
public class DemoBase { public void Method() { Console.WriteLine("Hello Base !"); } } public class Demo:DemoBase { public new void Method() { Console.WriteLine("Hello Demo !"); } } // more code ... object o = MakeObject(); DemoBase db = o as DemoBase; db.Method(); Demo d = o as Demo; d.Method(); // more code ...
上面的代码中 Demo 继承自 DemoBase ,好多开发人员看到这段代码就会认为两次调用 Method 方法的结果应该是相同的,但是实际运行后发现输出的结果是不同的。这是因为 Method 方法的输出结果取决于开发人员是利用 DemoBase 类型的引用来指代 Demo 对象,还是利用 Demo 类型来指代 Demo 对象。这里边虽然使用了 new 修饰符,但是它不会把非虚方法转化为虚方法,只会在类中增加一个方法。之所以会增加一个方法,是因为非虚方法是静态绑定的,只要是使用 DemoBase.Method 的地方都执行的是 DemoBase 里的 Method 方法,即使派生类里存在同名的方法也会忽略。
Tip:这里再提一句虚方法,虚方法是动态绑定的,只有到运行时才会根据对象的实际类型来确定应该调用哪个。
一、正确使用
讲到这里就引出了一个编码规则,非虚方法 不推荐 使用 new 操作符重新定义,也不能把所有的方法都设置为虚方法,因为这将订立契约告诉开发人员当前类的派生类可以重新实现所有的方法(虚方法的作用其实是用来描述基类与继承类的部分功能上的区别的)。除非是基类里面的方法和派生类中的方法重名的情况才可使用 new 修饰符。这种情况一般出现在基类和派生类已经被大量使用,修改派生类的方法名称会导致更大的修改,这时我们就可以在派生类中重名的方法上使用 new 操作符。我们在使用 new 修饰符前应该考虑清楚以后可能带来的后果,如果后其成本比直接修改名称要高,那么就应该修改派生类中重名的方法名称。
二、小结
只有当基类新增的方法名和派生类中的方法名重名时才可使用 new 修饰符,并且使用 new 修饰符前应该考虑清楚以后造成的后果。