方法签名中的新关键字


113

在执行重构时,我最终创建了一个类似于以下示例的方法。为了简单起见,已更改数据类型。

我以前有这样的作业说明:

MyObject myVar = new MyObject();

偶然地将其重构为:

private static new MyObject CreateSomething()
{
  return new MyObject{"Something New"};
}

这是我剪切/粘贴错误的结果,但是new关键字in private static new有效并且可以编译。

问题new关键字在方法签名中表示什么?我认为这是C#3.0中引入的?

override有何不同?


5
在方法隐藏的可取一些注意事项:blogs.msdn.com/ericlippert/archive/2008/05/21/...
埃里克利珀

2
@Eric ..很棒的帖子。我从来没有想到过用这种方式隐藏方法,因为是的,对象是一回事,但是我们现在将其作为其他东西来展示,因此我们希望将它作为AS展示的东西的行为。聪明...
BFree

1
将来有一个重复的问题,我尝试过详细回答:在c#中使用new关键字
Ken Kin

1
new在方法(或其他类型成员)上使用aa修饰符不是“ C#3.0中引入的内容”。自从C#的第一个版本以来,它就一直存在。
Jeppe Stig Nielsen 2013年

1
在这个问题中有4个重复的问题。我认为,这将为您提供最佳理解:stackoverflow.com/questions/3117838/…。@EricLippert回答。
雷科尔·阿玛罗(Raikol Amaro),

Answers:


101

来自MSDN的新关键字参考:

MSDN参考

这是我在网上从Microsoft MVP中找到的一个很好的示例: 链接到原始

public class A
{
   public virtual void One();
   public void Two();
}

public class B : A
{
   public override void One();
   public new void Two();
}

B b = new B();
A a = b as A;

a.One(); // Calls implementation in B
a.Two(); // Calls implementation in A
b.One(); // Calls implementation in B
b.Two(); // Calls implementation in B

替代只能在非常特殊的情况下使用。从MSDN:

您不能覆盖非虚拟或静态方法。覆盖的基本方法必须是虚拟的,抽象的或覆盖的。

因此,需要使用“ new”关键字来允许您“覆盖”非虚拟和静态方法。


4
我只是运行您的示例..即使您未指定“ new”,它也会覆盖它,对吧?
Michael Sync

2
正是@MichaelSync,所以为什么我们需要提及新关键字?
ZoomIn

2
“尽管无需使用new修饰符即可隐藏成员,但会收到编译器警告。” 根据链接的文档。因此,该关键字可以清楚表明您打算隐藏,并且不会发出警告。
吉姆·伯爵

1
-1->完全不需要-行为将是相同的。对于新手来说,这非常令人困惑new,但我认为这只是为了提高可读性-编译器只是在警告您,当您调用与基名称相同的派生类方法时,您可能不会得到基类的方法认为...。很奇怪...纯粹出于可读性?
Don Cheadle 2015年

1
为了完整起见:如果A和B类都实现了接口IMyInterface,则将调用Derived类上的实现。因此IMyInterface c = new B()将调用B类的执行。如果只有一个类实现该接口,则将调用实现该接口的类中的方法。
Nullius

61

不,它实际上不是“新的”(对双关语)。它基本上用于“隐藏”方法。IE浏览器:

public class Base
{
   public virtual void Method(){}
}

public class Derived : Base
{
   public new void Method(){}
}

如果您这样做,请执行以下操作:

Base b = new Derived();
b.Method();

Base中的方法将被调用,而不是派生方法。

一些更多信息:http : //www.akadia.com/services/dotnet_polymorphism.html

重新编辑:在我给出的示例中,如果要“覆盖”而不是“新”,则在调用b.Method()时;由于多态性,将调用派生类的方法。


公共类Base {公共虚拟void Method(){Console.WriteLine(“ Base”); }} public class Derived:Base {public void Method(){Console.WriteLine(“ Derived”); 基b = new Derived(); b.Method(); 我得到了“基地” ..如果我添加在派生类的“新”,我仍然得到“基地” ..
迈克尔同步

@michael方法仍然是虚拟的
Rune FS

@MichaelSync:您应该看到该代码的警告;警告Derived.Method()'隐藏继承的成员'Base.Method()'。要使当前成员重写该实现,请添加override关键字。否则,添加新关键字。
Christopher McAtackney 2011年

2
@MichaelSync如果忽略了“ override”一词,则默认行为是“ new”,例如方法隐藏。因此,您将新词保留在外的事实没有任何区别。
BFree

1
是。我也是这么想的。不知道为什么C#补充说:“新的”关键词..它只是为了使报警消失了.. stackoverflow.com/questions/8502661/...
迈克尔同步

22

正如其他人解释的那样,它用于隐藏现有方法。这对于重写在父类中不是虚拟的方法很有用。

请记住,创建“新”成员不是多态的。如果将对象强制转换为基本类型,则它将不使用派生类型的成员。

如果您有基类:

public class BaseClass
{
    public void DoSomething() { }
}

然后是派生类:

public class DerivedType : BaseClass
{
    public new void DoSomething() {}

}

如果您声明的类型DerivedType然后进行转换,则该方法DoSomething()不是多态的,它将调用基类的方法,而不是派生的方法。

BaseClass t = new DerivedType();
t.DoSomething();// Calls the "DoSomething()" method of the base class.

1
它将调用从基类中的方法,即使你从DerievedType删除“新”以及..
迈克尔同步

2
我认为您的第二段涉及整个主题。当处理来自基类引用的调用时,“ new”不是多态的。你得到什么,你当你调用中指定。“覆盖”是多态的...即。您将获得类层次结构指定的内容。
乔纳森·莱因哈特

怎么这样模糊地定义?对于新手来说非常沮丧。不,它与多态性无关-它具有与override方法签名中完全没有的行为完全相同的行为
Don Cheadle 2015年

什么隐藏了什么?肯定不能new从派生类型中隐藏基类型,因为您是否不能始终使用base.<type>符号访问基类型?
thatWiseGuy

@thatWiseGuy从某种意义上说,它是“隐藏的”,即在代码中使用派生类时不会调用基本方法。仍然可以在内部使用调用它base.<method>,如果在代码中强制转换为基本类型,也可以在外部调用它。将其视为“覆盖”基本方法比“隐藏”它在技术上更为准确。
丹·赫伯特

7

从文档:

如果派生类中的方法前面带有new关键字,则该方法被定义为独立于基类中的方法。

实际上这意味着什么:

如果您从另一个类继承,并且您拥有一个共享相同签名的方法,则可以将其定义为“新”,从而使其独立于父类。这意味着,如果您引用“父”类,则将执行该实现;如果您引用了子类,则将执行该实现。

我个人尝试避免使用'new'关键字,因为它通常表示我的类层次结构错了,但是有时它可能很有用。一个地方是版本控制和向后兼容。

MSDN中有很多有关此的信息


发生此行为的事实与new在那里无关。这是句法/可读性。
Don Cheadle

3

这意味着该方法用基类继承的相同名称替换方法。在您的情况下,您可能在基类中没有使用该名称的方法,这意味着new关键字完全多余。


3

长话短说-它不是必需的,它不会改变任何行为,并且纯粹出于可读性考虑。

这就是为什么在VS中您会看到一些混乱的原因,但是您的代码可以按预期的那样编译和运行得很好。

人们想知道,如果这是真的值得创建的new关键字时,它的意思是开发人员的承认“是的,我知道我躲在基方法,是的,我知道我没有做相关的任何事情virtualoverriden(多态性) -我真的很想创建它自己的方法”。

这对我来说有点奇怪,但可能仅是因为我来自Java背景,并且C#继承和Java:之间存在根本的区别:在中Java,方法默认情况下是虚拟的,除非由指定final。在中C#,除非由指定,否则方法默认为final / concrete virtual


1

MSDN

使用new修饰符可显式隐藏从基类继承的成员。若要隐藏继承的成员,请在派生类中使用相同的名称对其进行声明,然后使用new修饰符对其进行修改。


0

小心这个陷阱。
您有一个在基类中实现的接口中定义的方法。然后,您创建一个隐藏该接口的方法的派生类,但不要专门将派生类声明为实现该接口。如果然后通过对接口的引用调用该方法,则将调用基类的方法。但是,如果派生类确实实现了该接口,则无论使用哪种引用类型,都将调用其方法。

interface IMethodToHide
{
    string MethodToHide();
}

class BaseWithMethodToHide : IMethodToHide
{
    public string MethodToHide()
    {
        return "BaseWithMethodToHide";
    }
}

class DerivedNotImplementingInterface   : BaseWithMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedNotImplementingInterface";
    }
}

class DerivedImplementingInterface : BaseWithMethodToHide, IMethodToHide
{
    new public string MethodToHide()
    {
        return "DerivedImplementingInterface";
    }
}

class Program
{
    static void Main()
    {
        var oNoI = new DerivedNotImplementingInterface();
        IMethodToHide ioNoI = new DerivedNotImplementingInterface();

        Console.WriteLine("reference to the object type DerivedNotImplementingInterface calls the method in the class " 
            + oNoI.MethodToHide());
        // calls DerivedNotImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedNotImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioNoI.MethodToHide());
        // calls BaseWithMethodToHide.MethodToHide()
        Console.ReadLine();

        var oI = new DerivedImplementingInterface();
        IMethodToHide ioI = new DerivedImplementingInterface();

        Console.WriteLine("reference to the object type DerivedImplementingInterface calls the method in the class " 
            + oI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.WriteLine("reference to a DerivedImplementingInterface object via the interfce IMethodToHide calls the method in the class " 
            + ioI.MethodToHide());
        // calls DerivedImplementingInterface.MethodToHide()
        Console.ReadLine();

    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.