OK.我想我明白new
和override
之间的区别.但是,如果我的理解是正确的,那么new
关键词不是违背了OOP的原则吗?有了它,我可以在子类中创建一个与基类具有不同签名的方法,对吗?喜欢这个:
class MyBase
{
public int[] SampleMethod() { ... }
}
class MyChild : MyBase
{
public new string[] SampleMethod() { ... }
}
客户端希望从MyBase
继承的类具有一个名为 SampleMethod
的方法,该方法返回int
数组,但子类没有。这与我认为需要子方法与父方法具有相同签名override
不同。我错过了什么?
问题出在你这里的陈述中:
客户端希望从 MyBase 继承的类具有一个名为 SampleMethod 的方法,该方法返回一个 int 数组,但子类没有。
这是不真实的。 实际上,该类确实实现了该方法。 它还实现了自己的版本。
如果MyChild
的实例声明如下:
MyBase myBase = new MyChild();
这一行:
int[] ints = myBase.SampleMethod();
有效并调用所需的方法。 相比之下,这一行:
string[] strings = myBase.SampleMethod();
会失败。 但是,如果将其转换为MyChild
:
string[] strings = ((MyChild)myBase).SampleMethod();
这完全符合您的预期。
这里的要点是,由于已知变量是MyBase
的,无论您的new
实现如何,它的行为都将完全符合您的预期。 因此,多态性(因为它对编译时类型做出反应)不受影响,并且对任何 OOP 概念都没有影响。
我认为适用的原则是 Liskov 替换原则 (LSP),我同意您不应该在继承类中使用仅在输出类型上不同的方法。通常,人们会期望实现类对于由祖先定义的方法具有相同的语义,无论它是从类型为基类还是实现类的变量引用的。
然而,原则的问题在于它们是原则,而不是法律,有时可能需要违反它们。 话虽如此,我不记得使用new
关键字很长一段时间(如果有的话)来替换父类实现。
我认为对new
方法的需求是一种代码异味 - 暗示我的设计可能有问题。也许我试图在该类层次结构中做太多事情,或者我选择了错误的模式来应用。
我更喜欢 new
关键字,在这种情况下,继承的接口对方法或属性有更强的限制:
class Car
{
}
class Truck : Car
{
}
interface IDriver
{
Car Vehicle { get; }
}
class Driver : IDriver
{
public Car Vehicle { get; }
public Driver(Car vehicle)
{
Vehicle = vehicle;
}
}
interface ITrucker : IDriver
{
new Truck Vehicle { get; }
}
class Trucker : Driver, ITrucker
{
public new Truck Vehicle
{
get { return (Truck) base.Vehicle; }
}
public Trucker(Truck vehicle)
: base(vehicle)
{
}
}
当我得到一些显式ITrucker
对象时,我直接通过 Vehicle
属性获取其Truck
,并且不需要另一个强制转换,这在某些情况下非常方便。
无论如何,如果允许设置,这需要仔细处理此类属性。否则,可以很快获得无效的转换。对于只读属性,这有时非常方便。
它基本上用于隐藏基方法。如果您计划隐藏基类的方法,这是在派生类中标记方法的正确方法。如果不使用 new 关键字,则会收到编译器警告。
如果没有具有相同签名的基方法,则在派生类中使用 new 毫无意义。