在C#中使用’new’修饰符

我读到new修饰符隐藏了基类方法。

 using System; class A { public void Y() { Console.WriteLine("AY"); } } class B : A { public new void Y() { // This method HIDES AY // It is only called through the B type reference. Console.WriteLine("BY"); } } class Program { static void Main() { A ref1 = new A(); // Different new A ref2 = new B(); // Polymorpishm B ref3 = new B(); ref1.Y(); ref2.Y(); //Produces AY line #xx ref3.Y(); } } 

为什么ref2.Y(); 产生AY作为输出?

这是简单的多态,基类对象指向派生类,因此它应该调用派生类函数。 我实际上是Java兼C#编码器; 这些概念让我大吃一惊。

当我们说new隐藏基类函数时,这意味着无法调用类函数,就我所知,这就是隐藏的含义。

REF

在C#中,默认情况下方法不是虚拟的(与Java不同)。 因此, ref2.Y()方法调用不是多态的。

要从多态性中受益,您应该将AY()方法标记为virtual ,并将BY()方法标记为override

new修饰符所做的只是隐藏从基类inheritance的成员。 这就是你的Main()方法中真正发生的事情:

 A ref1 = new A(); A ref2 = new B(); B ref3 = new B(); ref1.Y(); // AY ref2.Y(); // AY - hidden method called, no polymorphism ref3.Y(); // BY - new method called 

(只是为了补充其他答案,以及我自己的评论。)

当使用new ,类(或结构或接口)将具有两个相同的成员,一个inheritance自基类型,另一个由类型本身声明。 避免这样!

重要提示:仅仅因为你说new ,你不会“删除”旧的成员。 它仍然存在,可以轻松调用。 new成员不会替换inheritance的成员。 它是一个无关的成员,恰好具有相同的名称。

在一个看起来相同的类型中拥有两个或更多成员是不好的。 这会导致混乱。 考虑一下代码:

 interface IOne { void Y(); } interface ITwo { void Y(); } interface IBoth : IOne, ITwo { } class Test { static void M(IBoth obj) { obj.Y(); // must not compile! } } 

IBoth类型有两个成员(都是inheritance的)看起来相同。 根据具体的类obj ,这些方法可能有不同的实现。 调用obj.Y()是不明确的。 您必须将obj为其中一个基接口才能解决此问题。

然后考虑这段代码:

 interface IBase { void Y(); } interface IDerived : IBase { /* new */ void Y(); } class Test { static void M(IDerived obj) { obj.Y(); // allowed; IDerived has two Y, but one hides the other } } 

这次,有两个Y() ,但有一个比另一个“更近”。 所以越近越好。 但是,如果不使用new ,编译器会给出警告。 如果你确实使用new ,除了使编译时警告消失之外什么都不会改变。 故意制作两个Y()真是个坏主意。

如果基本类型(此处为IBase )由其他供应商/供应商编写,则可能发生这种情况。 示例:在基础没有该function时,您可能在界面中引入了Y() 。 但随后IBase的供应商正在发布其产品的新版本,其中IBase具有Y() 。 现在,如果您针对新版本编译代码,“你的” Y()仍将被调用,而不是他们的。 但它会给出这个警告。 如果你包括new的警告就会消失。 但是,如果确定供应商的Y()完成工作,或者(2)将Y()方法重命名为某个未使用的名称,则最好(1)完全删除Y()方法。

如果你想要的是多态,当然使用abstract / virtual (仅限类成员)和override (在inheritance类中)。 override不会引入任何新成员,只是现有(inheritance)成员的新实现。 这可以仅针对非静态成员(通常是方法或属性)来完成。

对象的类型是A,但是ref2不访问在B类中定义的Y()版本,因为该方法是使用new修饰符而不是override修饰符声明的。 因此,ref2对象显示与A对象相同的描述。