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

时间:2014-04-02 11:13:06

标签: c# .net oop polymorphism new-operator

我读到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}据我所知,隐藏的是什么意思。

ref

3 个答案:

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