我读到new
修饰符隐藏了基类方法。
using System;
class A
{
public void Y()
{
Console.WriteLine("A.Y");
}
}
class B : A
{
public new void Y()
{
// This method HIDES A.Y.
// It is only called through the B type reference.
Console.WriteLine("B.Y");
}
}
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 A.Y line #xx
ref3.Y();
}
}
为什么ref2.Y();
会产生A.Y
作为输出?
这是简单的多态,基类对象指向派生类,因此它应该调用派生类函数。我实际上是Java兼C#编码器;这些概念让我大吃一惊。
当我们说new
隐藏基类函数时,这意味着无法调用 base 类函数,这就是&#39}据我所知,隐藏的是什么意思。
答案 0 :(得分:23)
在C#中,默认情况下方法不是虚拟的(与Java不同)。因此,ref2.Y()
方法调用不是多态的。
要从多态性中受益,您应将A.Y()
方法标记为virtual
,将B.Y()
方法标记为override
。
new
修饰符所做的只是隐藏从基类继承的成员。这就是你的Main()
方法中真正发生的事情:
A ref1 = new A();
A ref2 = new B();
B ref3 = new B();
ref1.Y(); // A.Y
ref2.Y(); // A.Y - hidden method called, no polymorphism
ref3.Y(); // B.Y - new method called
答案 1 :(得分:5)
(只是为了补充其他答案,以及我自己的评论。)
当使用new
时,类(或结构或接口)将具有两个相同的成员,一个继承自基类型,另一个由类型本身声明。避免这样!
重要提示:仅仅因为您说new
,您就不会删除"老会员。它仍然存在,可以轻松调用。 new
成员不会替换继承的成员。它是一个无关的成员,恰好有相同的名字。
在一个看起来相同的类型中拥有两个或更多成员是不好的。这会导致混乱。考虑一下代码:
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
有两个成员(都是继承的),看起来相同。根据具体类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()
,但有一个是#34;更接近"比另一个。所以越近越好。但是,如果您不使用new
,编译器会向您发出警告。如果你使用new
,那除了使编译时警告消失之外什么都不会改变。有目的地制作两个Y()
真是个坏主意。
如果基本类型(此处为IBase
)由其他供应商/供应商编写,则可能发生这种情况。示例:在基础没有该功能的时候,您可能在界面中引入了Y()
。但是IBase
的供应商正在发布其IBase
具有Y()
的新产品版本。现在,如果您针对新版本编译代码,"您的" Y()
仍将被召唤,而不是他们的。但它会给出这个警告。如果您添加new
,警告就会消失。但是,如果您确定供应商Y()
完成工作,或者(2)将您的Y()
方法重命名为{1}}方法,则最好(1)完全删除Y()
方法一些未使用的名字。
如果你想要的是多态,当然使用abstract
/ virtual
(仅限类成员)和override
(在继承类中)。 override
不会引入任何新成员,只是现有(继承)成员的新实现。这可以仅针对非静态成员(通常是方法或属性)完成。
答案 2 :(得分:1)
对象的类型是A,但是ref2不访问在B类中定义的Y()版本,因为该方法是使用new修饰符声明的,而不是覆盖修饰符。因此,ref2对象显示与A对象相同的描述。