控制台输出基础知识

18

我对以下代码有一个问题:

class CurrentDate
    {
        static void Main()
        {
            Console.WriteLine(DateTime.Now);
        }
    }

文档说:

  

使用指定的格式信息,将指定对象数组的文本表示形式及当前行终止符写入标准输出流。

那么我的问题是:为什么WriteLine知道DateTime对象的文本表示形式呢?我的意思是,如果我从我的类创建自己的对象,它如何知道如何将该值转换为文本?更重要的是,它如何知道值是什么?如何定义对象的“值”?


请参见 https://msdn.microsoft.com/zh-cn/library/ms173154(v=vs.80).aspx。 - adaam
请注意,Visual Studio调试器的对象检查器也使用非常类似的机制(MyClass.toString)来确定在将对象显示为单行时要打印的值。 - Superbest
Console.WriteLine() 隐式调用 ToString() 方法,因此对于您自己的对象,您必须实现/重写 ToString() 方法。 - Jaider
3个回答

18

为什么 WriteLine 知道 DateTime 对象的文本表示方式?我的意思是,如果我从自己的类创建自己的对象,它将如何知道如何将值转换为文本?

Console.WriteLine 有一组匹配特定类型(主要是基元类型)的重载。如果编译器无法将提供的类型与重载匹配,则匹配使用 System.Object 的重载(只要您提供单个参数)。如果发生这种情况,它会检查该类型是否实现了 IFormattable,如果实现了,则调用 IFormattable.ToString(null,Formatter)。如果没有,则在您的对象上调用 ToStringToString 在所有对象都继承的 System.Object 中定义。每个想要自定义表示形式的对象都会覆盖默认行为,就像 DateTime 一样。

例如,假设你有一个名为 Foo 类的字符串属性 Bar,并且当将你的 Foo 传递给 Console.WriteLine 时,你希望它打印出一些有意义的东西:
public class Foo
{
    public string Bar { get; set; }
    public override string ToString()
    {
         return Bar;
    }
}

现在我们想要传递它Console.WriteLine

public static void Main(string[] args)
{
      var foo = new Foo { Bar = "bar" };
      Console.WriteLine(foo);
}

会产生 "bar"。


9
由于Console.WriteLine(DateTime)没有重载,所以在您的情况下,调用Console.WriteLine(Object)重载,该重载会调用TextWriter.WriteLine(object)重载,其实现方式为此重载调用TextWriter.WriteLine(object)重载
IFormattable f = value as IFormattable;
if (f != null)
    WriteLine(f.ToString(null, FormatProvider));
else
    WriteLine(value.ToString());

如您所见,此方法检查此对象类型是否实现IFormattable接口。由于Datetime实现了该接口,因此将调用f.ToString(null, FormatProvider)。从此方法的文档中,第一个参数是:

空引用(Visual Basic中的Nothing),用于使用IFormattable实现类型定义的默认格式

而从DateTime.ToString(String, IFormatProvider)方法的文档中可以看到:
如果格式为 null 或空字符串(""),则使用标准格式说明符 "G"。这意味着表示将是 ShortDatePatternLongTimePattern 属性的组合,它们属于您的 CurrentCulture。如果您想要自定义类的特殊格式,可以 重写 .ToString() 方法 来更改其行为。

7
与一些人的想法相反,DateTime.ToString()不会被调用。在.NET中,一个对象有两种将自己“字符串化”的方式:重写 string Object.ToString() 方法和实现IFormattable 接口。DateTime二者皆备。

现在... 当你试图执行以下操作时:

Console.WriteLine(DateTime.Now);

空白public static void WriteLine(Object value)重载被选中(在Visual Studio中Ctrl +单击WriteLine时可以看到)。 该方法只是调用TextWriter.WriteLine(value)方法,该方法执行以下操作:
IFormattable f = value as IFormattable;
if (f != null)
    WriteLine(f.ToString(null, FormatProvider));
else
    WriteLine(value.ToString());

通过使用ILSpy并查找Console.WriteLine,所有这些都可以轻松地看到。


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