【问题标题】:.NET Console.WriteLine Method ToString Behavior.NET Console.WriteLine 方法 ToString 行为
【发布时间】:2019-07-01 07:56:42
【问题描述】:

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

【问题讨论】:

  • 您必须重写 ToString,否则您只是将其隐藏在 Object 中,并且您的 ToString 不会在 Console.WriteLine(p) 上调用,只有当您直接调用它时。

标签: .net tostring


【解决方案1】:

当你重写一个方法时,你基本上是把一个新的实现放入一个“槽”1,它已经被你的基类指定为那个方法。当您隐藏一个方法(不要使用覆盖)时,您正在使用您的基类使用的名称并将该名称分配给一个不同的“槽”。

当编译器执行名称/重载解析时,它基本上试图决定将方法调用路由到哪个“槽”(因为由于重载,您可能有多个具有相同名称的方法,但它们会有不同的“插槽”)。

Console.WriteLine 被编译时,编译器可以为ToString 选择的唯一槽是Object ToString 方法声明的槽。所以这是它会调用的唯一方法2


1我在这里使用“插槽”是因为,虽然你不会发现它在 C# 规范中使用,但据我所知,在 CLR 级别,阴影方法被标记newslot

2不是 100% 确定它确实确实调用了 ToString 本身,而不是通过任何数量的间接调用,但在这里说它确实足够了。

【讨论】:

    【解决方案2】:

    Console.WriteLine(p) 调用对象的ToString 方法,因为ToString 方法未被覆盖。

    public String ToString()
    

    此方法隐藏了基类的ToString 方法,不会覆盖它。这就是输出不同的原因。要正确覆盖 ToString 方法,您必须在方法声明中添加 override 关键字。

    【讨论】:

      【解决方案3】:

      我已经修改了你的代码,所以它可以编译,你可以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() 时,它正在访问您尚未覆盖的虚拟成员。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-08
        • 2023-02-26
        • 2016-07-21
        • 1970-01-01
        • 1970-01-01
        • 2020-01-01
        • 2021-10-03
        • 1970-01-01
        相关资源
        最近更新 更多