代码改变世界

Effective C# 学习笔记(三十三) 只在更新基类时,使用new关键字

2011-07-18 12:44  小郝(Kaibo Hao)  阅读(300)  评论(0编辑  收藏  举报

对于new关键字在修饰方法的使用我们要小心,因为它并不是像看上去那样会把父类nonVirtual的方法,转为virtual方法。

首先,看一个例子:

object c = MakeObject();

// Call through MyClass reference:

MyClass cl = c as MyClass;

cl.MagicMethod();

// Call through MyOtherClass reference:

MyOtherClass cl2 = c as MyOtherClass;

cl2.MagicMethod();

When the new modifier is involved, that just isn’t the case:

public class MyClass

{

public void MagicMethod()

{

Console.WriteLine("MyClass.MagicMethod");

}

}

public class MyOtherClass : MyClass

{

// Redefine MagicMethod for this class.

public new void MagicMethod()

{

Console.WriteLine("MyOtherClass.MagicMethod");

}

}

上面的代码经常会让人误以为MyOtherClass的实现会覆盖掉MyClassMagicMethod方法的实现,但事实上两个类的方法会在对象的引用不同时调用不同的方法。如:

上例中奖 cl2对象再次转换为MyClass对象后,其又会执行MyClassMagicMethod方法。这样就会给人以误解,同样一个对象,只是因为引用类型不同则同样的方法的执行逻辑就不一致。

 

其实new关键字的适用场景一般只有在父类的新方法与子类的已有方法重名时起到覆盖父类重名方法的作用。

例如下面代码中MyWidget继承自BaseWidget,而MyWidget有一个方法NormalizeValues,该类已被其类的消费者使用。这时父类发布了新版本,添加了新feature但是其添加了一个同名的NormalizeValues方法,所以你需要使用new关键字来覆盖合并父类的逻辑。

public class MyWidget : BaseWidget

{

public void new NormalizeValues()

{

// details elided.

// Call the base class only if (by luck)

// the new method does the same operation.

base.NormalizeValues(); //别忘了调用父类的逻辑

}

}

 

若你能修改父类的代码,还是最好把父类的方法名改为它名,因为你的子类可能已被许多用户使用了,所以为了最小化工作量,还是让父类新增方法不要与子类的旧方法冲突的好。还有用户可能还需直接使用父类的方法,若你不能修改父类的方法名称,你可能必须修改你子类的方法了,但是长痛不如短痛,这样你以后也不必为这些重名的方法进行额外的维护了,尤其是在需求多变的情况下。