'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替代原则吗?
干杯。
答案 0 :(得分:2)
关于LSP
这不会破坏LSP。
LSP指出如果Derived
是Base
的子类型,那么任何代码都取决于Base
(例如,具有Base
参数的方法,例如void DoSomething(Base b)
)可以用Derived
的实例替换,没有任何令人惊讶的效果。
正如您所指出的,如果您将Derived
的实例分配给Base
变量,则会调用Base
实现。
这是预期的行为,因为Say
不是虚拟的。这意味着针对Base
变量编写的代码需要调用Base
实现。
实用目的
您可以将new
方法视为规避不可覆盖方法的一种方法 - 并提出警告!您必须针对该特定类型进行编程 - 而不是其界面。
答案 1 :(得分:1)
虽然这样做不是一个好习惯,但是当你从第三方程序集继承时(即你无法控制的代码)并且你希望对方法有不同的行为时,我会发现它很有用。
答案 2 :(得分:1)
如果派生类中的方法具有相同的名称和参数列表,则该方法被认为与其基类中的方法“相关”。编译器设计者有两种处理这种相关方法的方法:
virtual
/ override
指定相关方法,并使用{{1}指定不相关的方法}。处理兴高采烈的方法的第一种方法让程序员别无选择:如果他们想要一个不相关的方法,他们必须给它一个不同的名字。第二种方式是让程序员选择,而不是更冗长。
基本上,new
关键字允许您与编译器通信,您添加的方法与基类中具有相同名称和参数的方法无关。
这不会打破Liskov替代原则吗?
可以说,它没有:派生类引入了一个具有相同名称和参数的方法,程序员明确指定为与基础中的方法无关,这一事实不会改变派生行为中的任何内容在用作其基类的替身的情况下的类。
答案 3 :(得分:1)
它只允许用户重新定义基类中的方法。当然,如果开发人员预见到这种偶然事件,您希望他们将其编码为虚拟(用于默认实现)或抽象(需要指定任何实现)。
LSP只是简单地要求基类和子类可以互换使用,所以这并不违反我所见的原则。
C#的一个缺点是只能继承一个类,因此对于需要多个接口实现的复杂系统来说,这样的情况应该相对较少。
答案 4 :(得分:1)
当Base
和Derived
的客户无法控制时,此功能非常有用。假设你是从这开始的。
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();
}
}