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

12 .net c# oop polymorphism new-operator

我读到newmodifer隐藏了基类方法.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

REF

Ser*_*diy 24

在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
Run Code Online (Sandbox Code Playgroud)

  • @ user1765876`ref2`的_compile-time type_是`A`.但是,对象`ref2`的_run-time type_是'B`.执行`ref2.MemberThatDoesNotExistInA`是编译时错误.做`ref2.MemberFromA`就行了.如果成员是非虚拟的(没有`virtual`,`abstract`或`override`修饰符),你可以从`A`类获得实现.只有当成员是"虚拟"时才能获得被覆盖的实现(如果`B`提供了一个). (2认同)

Jep*_*sen 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!
  }
}
Run Code Online (Sandbox Code Playgroud)

该类型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
  }
}
Run Code Online (Sandbox Code Playgroud)

这一次,有两个Y(),但有一个比另一个"更近".所以越近越好.但是,如果您不使用,编译器会给您一个警告new.如果您使用new,除了使编译时警告消失外,其他任何变化都没有.Y()故意制作两个真是个坏主意.

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

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