"new"关键字(用于方法)和 OOP



OK.我想我明白newoverride之间的区别.但是,如果我的理解是正确的,那么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 毫无意义。

最新更新