题
在执行重构时,我最终创建了一个类似下面示例的方法。为简单起见,数据类型已更改。
我之前有这样的作业声明:
MyObject myVar = new MyObject();
这是偶然的重构:
private static new MyObject CreateSomething()
{
return new MyObject{"Something New"};
}
这是我的剪切/粘贴错误的结果,但 private static new
中的 new
关键字有效并编译。
问题: new
关键字在方法签名中表示什么?我假设它是在C#3.0中引入的东西?
这与 override
有什么不同?
解决方案
来自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'关键字来“覆盖”非虚拟和静态方法。
其他提示
不,它实际上不是“新的” (原谅双关语)它基本上用于“隐藏”。一个方法。 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();由于多态性,将调用Derived类的Method。
正如其他人所解释的那样,它用于隐藏现有方法。它可用于覆盖父类中非虚拟的方法。
请注意,创建“新”字样成员不是多态的。如果将对象强制转换为基类型,则不会使用派生类型的成员。
如果您有基类:
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.
来自文档:
如果派生类中的方法前面带有new关键字,则该方法被定义为独立于基类中的方法。
这在实践中意味着什么:
如果从其他类继承并且您有一个共享相同签名的方法,则可以将其定义为“new”,以使其独立于父类。这意味着如果你有对'parent'类的引用,那么将执行该实现,如果你有对子类的引用,那么将执行该实现。
就个人而言,我试图避免使用'new'关键字,因为它通常意味着我的类层次结构错误,但有时它可能有用。一个地方是版本控制和向后兼容性。
这意味着该方法使用基类继承的相同名称替换方法。在您的情况下,您可能在基类中没有该名称的方法,这意味着新关键字完全是多余的。
长话短说 - 它不是必需的,它会改变NO行为,并且为了便于阅读,它很自然。
这就是为什么在VS中你会看到一点点波浪形,但你的代码将编译并运行完全正常并且符合预期。
人们不得不怀疑是否真的值得创建 new
关键字,只要它意味着开发人员承认“是的,我知道我隐藏了一个基本方法,是的我知道我”我没有做任何与 virtual
或 overriden
(多态)相关的事情 - 我真的只想创建它自己的方法“。
这对我来说有点奇怪,但也许只是因为我来自 Java
背景而且 C#
继承和 Java
:在 Java
中,默认情况下方法是虚拟的,除非 final
指定。在 C#
中,除非由 virtual
指定,否则方法默认为final /具体。
来自 MSDN :
使用new修饰符显式隐藏从a继承的成员 基类。要隐藏继承的成员,请在派生中声明它 使用相同名称的类,并使用new修饰符修改它。
小心这个问题。
您有一个在基类中实现的接口中定义的方法。然后创建一个隐藏接口方法的派生类,但不要将派生类声明为实现接口。如果然后通过对接口的引用调用该方法,则将调用基类的方法。
但是,如果派生类确实实现了接口,那么无论使用哪种类型的引用,都会调用其方法。
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();
}
}