119

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

我以前有一个这样的赋值语句:

MyObject myVar = new MyObject();

它被偶然重构为:

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

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

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

这与 有何不同override

4

9 回答 9

105

来自 MSDN 的新关键字参考:

MSDN 参考

这是我在网上从 Microsoft MVP 中找到的一个非常有意义的示例: Link to Original

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'关键字来允许你'覆盖'非虚拟和静态方法。

于 2009-06-18T18:25:32.287 回答
62

不,它实际上不是“新的”(请原谅双关语)。它基本上用于“隐藏”一种方法。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(); 由于多态性,将调用派生类的方法。

于 2009-06-18T18:14:28.433 回答
23

正如其他人解释的那样,它用于隐藏现有方法。它对于覆盖父类中非虚拟的方法很有用。

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

如果你有一个基类:

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.
于 2009-06-18T18:31:11.043 回答
7

从文档:

如果派生类中的方法以 new 关键字开头,则该方法被定义为独立于基类中的方法。

这在实践中意味着什么:

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

就我个人而言,我尽量避免使用“new”关键字,因为它通常意味着我的类层次结构错误,但有时它会很有用。一个地方是版本控制和向后兼容性。

MSDN 中有很多关于此的信息。

于 2009-06-18T18:15:13.847 回答
4

长话短说——它不是必需的,它不会改变任何行为,而且它纯粹是为了可读性。

这就是为什么在 VS 中你会看到一些波浪状的东西,但你的代码会编译并运行得非常好,并且符合预期。

人们不得不怀疑是否真的值得创建new关键字,而这意味着开发人员承认“是的,我知道我隐藏了一个基本方法,是的,我知道我没有做任何与virtualoverriden(多态性)相关的事情——我真的很想创建它自己的方法”。

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

于 2015-06-22T22:32:38.900 回答
3

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

于 2009-06-18T18:16:15.763 回答
1

来自MSDN

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

于 2009-06-18T18:15:21.350 回答
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();

    }
}
于 2016-05-31T18:01:41.620 回答
0

FWIW,我已经编写 C# 代码很长一段时间了,我需要new关键字的唯一情况是以下 OO 层次结构场景:

public abstract class Animal
{
    protected Animal(Animal mother, Animal father)
    {
        Mother = mother;
        Father = father;
    }

    public Animal Mother { get; }
    public Animal Father { get; }
}

public class Dog : Animal
{
    public Dog(Dog mother, Dog father)
        : base(mother, father)
    {
    }

    public new Dog Mother => (Dog)base.Mother;
    public new Dog Father => (Dog)base.Father;
}

几点说明:

  • 没有违反 OO 规则,基类仍然可以正常工作。
  • 属性不是virtual故意标记的,它们不需要。
  • 事实上,由于新的关键字,我们执行了更多的 OO 规则:狗不能有任何动物作为父亲/母亲。一定是条狗。
  • 使用new关键字是因为我们不能仅通过更改其返回类型来“覆盖”属性(或方法)。new是拥有良好 OO 层次结构的唯一方法。
于 2021-01-24T07:45:40.573 回答