C#: public new string ToString() 和 public override string ToString() 的区别是什么?

21

我希望重新定义一个类中的ToString()函数。

我写了:

public string ToString()

我正在使用一个HTML段落标签,它可以正确工作。但是ReSharper提示我将其更改为

标签。

public new string ToString() 

或者

public override string ToString()

有何不同?为什么C#需要像这样的东西?


+1 因为你用明智的方式拼写了你的名字 ;-p(并且这是一个合理的问题...) - Marc Gravell
9个回答

36
如果你使用public string ToString(),那么你的意图不够明确。如果你想通过多态性改变ToString的行为,那么请使用override。你可以添加一个新的ToString(),但这样做很愚蠢,请不要这样做!
区别在于当你执行以下操作时会发生什么:
MyType t = new MyType();
object o = t;
Console.WriteLine(t.ToString());
Console.WriteLine(o.ToString());

如果你使用override,两个版本都会输出你的新版本。如果你使用new,只有第一个版本会使用你的新版本;第二个版本将使用原始实现。
我认为我从来没有看到过任何人在ToString()上使用方法隐藏(又称new)。

不幸的是,我看到了几个 C# 中方法隐藏的例子。它们都不太好看。 - JaredPar
当然,方法隐藏并不是那么罕见的事情 - 我只是从来没有在ToString()上看到过它 ;-p 但是在更广泛的背景下,DbConnection.CreateCommand是一个经典的例子... - Marc Gravell
谢谢这个解释。但我有一个简单的问题,如果使用非常受控制(从未在父级上调用ToString()),那么方法隐藏在运行时更快吗?我想说应该是! - Nicolas Guillaume
@Niklaos 我有所怀疑;即使是这样,也不会有太大的影响——实例方法总是使用“callvirt”,即使是非虚拟方法。JIT可能会进行优化,但是…… - Marc Gravell

9
问题在于ToString是一个虚方法。为了在C#中重写虚方法,你需要指定override关键字。
你几乎肯定不想要“new”版本。

4

新修饰符将隐藏或“遮蔽”基类中具有相同签名的成员,而覆盖提供了从基类继承的成员的新实现。这是一篇好文章,介绍了遮蔽和覆盖之间的区别。


2
您想要覆盖。在您的情况下使用“new”进行隐藏并没有真正的优势。
这里有一篇关于覆盖和隐藏的区别的文章。

1

C#本身不需要,但Resharper需要。这是因为这两个关键字代表着显著不同的行为,如果你不指定,那么读取你代码的人可能无法完全清楚默认行为是什么(它是new)。

在这种情况下,你明显想要覆盖默认行为。


1
实际上,即使没有R#,你也会收到关于这个的警告。语言并不要求它,但即使是“express”(免费)的IDE也知道这是一个坏主意。 - Marc Gravell

1

ToString是基类中的虚方法。如果要使当前成员覆盖该实现,请添加override关键字。否则,添加new关键字。


0

你所做的一切都取决于你想要的行为。本文解释了ToString方法的行为方式,具体取决于你如何定义该方法以及在类层次结构中调用ToString的级别。


0
我个人的建议是不要使用隐藏;它会引起许多歧义,解决很少的问题。

0

在.NET中,ToString()方法适用于每种类型,因为该方法在基本的System.Object类中定义为虚拟方法,并且所有类型直接或间接继承自System.Object。如果默认的ToString()方法实现不能满足您的需求,您可以选择重写(使用override关键字)或隐藏(使用new关键字)它。

我找到了以下两篇优秀的文章,解释了重写ToString()方法的原因,以及方法隐藏和方法重写之间的区别。还有一个关于相同概念的YouTube视频。
重写ToString()方法的原因
方法隐藏和方法重写的区别


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接