在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对象相同的描述。