据我所知,.NET Console.WriteLine方法调用Class的ToString方法。在下面的代码中,Console.WriteLine(object)调用和Console.WriteLine(object.ToString())调用产生不同的输出。如果在下面的代码中将override关键字添加到ToString方法,则输出将相同。但是我想知道为什么输出在第一种情况下会有所不同。
程序输出:
TestOverrideConsole.Program(类名)
您好,来自计划
class Program
{
static void Main(string[] args)
{
Program p = new Program();
Console.WriteLine(p);
Console.WriteLine(p.ToString());
Console.ReadLine();
}
public String ToString()
{
return "Hello from Program";
}
}
答案 0 :(得分:0)
重写方法时,基本上是在将新的实现放入“插槽” 1 中,该插槽已经由基类指定为该方法。当您对方法进行阴影处理(不使用覆盖)时,您将获取基类使用的名称,并将该名称分配给不同“ slot”。
当编译器执行名称/重载解析时,它基本上试图确定是哪个“插槽”来路由方法调用(由于重载,您可能有多个具有相同名称的方法,但是它们将具有不同的“广告位”。
编译Console.WriteLine
时,编译器可以为ToString
选择的唯一插槽是Object
为其 ToString
方法声明的插槽。 。因此,这是它唯一会调用的 2 。
1 我在这里使用“插槽”是因为,尽管您不会在C#规范中找到它,但据我记得,在CLR级别上,标记了阴影方法与newslot
。
2 不能100%地确定它本身确实会调用ToString
,而不是通过任何数量的间接调用,但是在这里说它确实足够了。
答案 1 :(得分:0)
Console.WriteLine(p)
调用对象的ToString
方法,因为ToString
方法没有被覆盖。
public String ToString()
此方法隐藏基类的ToString
方法,并且不覆盖它。这就是输出不同的原因。要正确覆盖ToString
方法,您必须将override关键字添加到方法声明中。
答案 2 :(得分:0)
我已经修改了您的代码,使其可以编译,您可以inspect it here,
using System;
public static class Program
{
static void Main(string[] args)
{
var p = new P();
Console.WriteLine(p);
Console.WriteLine(p.ToString());
}
}
class P
{
public String ToString()
{
return "Hello from Program";
}
}
您会发现编译器发出此警告
警告CS0114:“ P.ToString()”隐藏继承的成员 'object.ToString()'。要使当前成员覆盖该成员 实施中,添加override关键字。否则添加新 关键字。
我认为这很容易解释。
WriteLine()
调用ToString()
时,它正在访问您尚未覆盖的虚拟成员。