.NET Console.WriteLine方法ToString行为

时间:2019-02-07 08:39:35

标签: .net tostring

据我所知,.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";
    }
}

3 个答案:

答案 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()时,它正在访问您尚未覆盖的虚拟成员。