会员隐藏,其实际目的是什么

时间:2013-12-18 11:09:08

标签: c# oop new-operator liskov-substitution-principle

'new' modifier的实际用途是什么?

public class Base
{
    public void Say()
    {
        Console.WriteLine("Base");
    }
}

public class Derived:Base
{
    public new void Say()
    {
        Console.WriteLine("Derived");
    }
}

如果这不能编译会不会更好?这段代码:

        Derived d = new Derived();
        d.Say();
        ((Base)d).Say();

返回

 Derived
 Base

这不会打破Liskov替代原则吗?

干杯。

5 个答案:

答案 0 :(得分:2)

关于LSP

这不会破坏LSP。 LSP指出如果DerivedBase的子类型,那么任何代码都取决于Base(例如,具有Base参数的方法,例如void DoSomething(Base b) )可以用Derived的实例替换,没有任何令人惊讶的效果。

正如您所指出的,如果您将Derived的实例分配给Base变量,则会调用Base实现。

这是预期的行为,因为Say不是虚拟的。这意味着针对Base变量编写的代码需要调用Base实现。

实用目的

您可以将new方法视为规避不可覆盖方法的一种方法 - 并提出警告!您必须针对该特定类型进行编程 - 而不是其界面。

答案 1 :(得分:1)

虽然这样做不是一个好习惯,但是当你从第三方程序集继承时(即你无法控制的代码)并且你希望对方法有不同的行为时,我会发现它很有用。

答案 2 :(得分:1)

如果派生类中的方法具有相同的名称和参数列表,则该方法被认为与其基类中的方法“相关”。编译器设计者有两种处理这种相关方法的方法:

  1. 依靠约定 - 例如,他们可以声明这样的方法是覆盖; Java就是这么做的。
  2. 请求程序员明确指示 - C#设计人员采用了这条路线:他们要求程序员使用virtual / override指定相关方法,并使用{{1}指定不相关的方法}。
  3. 处理兴高采烈的方法的第一种方法让程序员别无选择:如果他们想要一个不相关的方法,他们必须给它一个不同的名字。第二种方式是让程序员选择,而不是更冗长。

    基本上,new关键字允许您与编译器通信,您添加的方法与基类中具有相同名称和参数的方法无关。

      

    这不会打破Liskov替代原则吗?

    可以说,它没有:派生类引入了一个具有相同名称和参数的方法,程序员明确指定为与基础中的方法无关,这一事实不会改变派生行为中的任何内容在用作其基类的替身的情况下的类。

答案 3 :(得分:1)

它只允许用户重新定义基类中的方法。当然,如果开发人员预见到这种偶然事件,您希望他们将其编码为虚拟(用于默认实现)或抽象(需要指定任何实现)。

LSP只是简单地要求基类和子类可以互换使用,所以这并不违反我所见的原则。

C#的一个缺点是只能继承一个类,因此对于需要多个接口实现的复杂系统来说,这样的情况应该相对较少。

答案 4 :(得分:1)

BaseDerived的客户无法控制时,此功能非常有用。假设你是从这开始的。


public class Base
{
  // there is no Say method in Base!
}

public class Derived:Base
{
    public /*new*/ void Say() // we don't need new here
    {
        Console.WriteLine("Derived");
    }
}

有一天,那些负责Base的人在那里添加了酷Say方法。您可以重命名Derived.Say,但已经在其他地方使用过您无法更改的代码。因此,您使用new来避免中断Derived中的更改。


public class Base
{
    public void Say()
    {
        Console.WriteLine("Base");
    }
}

public class Derived:Base
{
    public new void Say()
    {
        Console.WriteLine("Derived");
    }
}

public class SomeClient
{
    public void Run()
    {
        var d = new Derived();
        d.Say();
    }
}