方法签名中的新关键字

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

我之前有一个这样的任务说明:

MyObject myVar = new MyObject();

它被意外地重构成这样:

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

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

问题 : new关键字在方法签名中意味着什么? 我假设它是 C # 3.0中引入的?

How does this differ from override?

91454 次浏览

不,它实际上不是“新的”(原谅这个双关语)。它基本上是用来“隐藏”一个方法的。 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

关于你的编辑: 在我给出的例子中,如果你要“覆盖”而不是使用“ new”,那么当你调用 b 方法()时; 派生类的方法会因为多态性而被调用。

来自文件:

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

这在实践中意味着什么:

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

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

这个 MSDN里有很多信息。

From MSDN:

使用新修饰符显式隐藏从 若要隐藏继承的成员,请在派生的 类,并使用新的修饰符修改它。

It means the method replaces a method by the same name inherited by the base class. In your case, you probably don't have a method by that name in the base class, meaning the new keyword is totally superfluous.

来自 MSDN 的新关键字引用:

MSDN 参考资料

下面是我在网上找到的一个来自微软 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:

不能重写非虚拟或 静态方法。重写的基 method must be virtual, abstract, or 重写。

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

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

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

If you have a base class:

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

And then the derived class:

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


}

如果您声明一个 DerivedType类型,然后强制转换它,那么方法 DoSomething()不是多态的,它将调用基类的方法,而不是派生的方法。

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

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

这就是为什么在 VS 中你会看到一些弯弯曲曲的东西,但是你的代码可以完美地编译和运行,正如预期的那样。

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

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

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

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();


}
}

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的,它们不需要标记为 virtual
  • 事实上,我们实施了更多的 OO 规则,多亏了新的关键字: 狗 不能有任何动物作为父亲/母亲。它是一只狗。
  • the new keyword is used because we cannot "override" a property (or method) just by changing its return type. new is the only way to have a nice OO hierarchy.