Console.Writeline 基础知识

Console.Writeline basics

我对以下代码有疑问:

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

文档说:

Writes the text representation of the specified array of objects, followed by the current line terminator, to the standard output stream using the specified format information.

所以我的问题是:WriteLine 怎么知道 DateTime 对象的文本表示?我的意思是,如果我从我自己的 class 创建我自己的对象,它怎么知道如何将值转换为文本?更重要的是,它怎么知道值是多少?如何定义对象的 "value"?

由于 Console.WriteLine(DateTime) 没有重载,在您的情况下,调用 Console.WriteLine(Object) 重载并且 this overload calls the TextWriter.WriteLine(object) overload which is implemented as:

IFormattable f = value as IFormattable;
if (f != null)
    WriteLine(f.ToString(null, FormatProvider));
else
    WriteLine(value.ToString());

如您所见,此方法检查此对象类型是否实现 IFormattable interface or not. Since Datetime implements this interface, your f.ToString(null, FormatProvider) will be called. From this method's documentation 第一个参数是:

A null reference (Nothing in Visual Basic) to use the default format defined for the type of the IFormattable implementation.

并且来自 DateTime.ToString(String, IFormatProvider) 方法的文档:

If format is null or an empty string (""), the standard format specifier, "G"., is used.

这意味着,表示将是 ShortDatePattern and LongTimePattern properties belonging to your CurrentCulture

的组合

如果您想要自定义的特殊格式 class,您可以 override the .ToString() method 您的类型来更改其行为。

How come WriteLine knows the text representation of DateTime object? I mean, if I create my own object from my own class, how would it know how to convert the value to text?

Console.WriteLine 有一个 set of overloads matching specific types (mainly primitives). If the compiler doesn't match an overload with the provided type, it matches with the overload taking System.Object (granted you provide a single parameter). If that happens, it checks to see if the type implements IFormattable, if it does, it invokes IFormattable.ToString(null, Formatter)。如果没有,它会在您的对象上调用 ToStringToStringSystem.Object 中定义,所有对象都从中继承。每个需要自定义表示的对象都会覆盖默认行为,就像 DateTime 那样。

例如,假设您有一个 Foo class 和 Bar 字符串 属性,并且您希望 Console.WriteLine 在以下情况下打印一些有意义的内容将您的 Foo 传递给它:

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".

与某些人的想法相反,DateTime.ToString() 不会 被调用。在 .NET 中,对象可以通过两种方式实现 "stringize" 自身:覆盖 string Object.ToString() 方法和实现 IFormattable 接口。 DateTime 两者兼而有之。

现在...当你尝试做

Console.WriteLine(DateTime.Now);

void public static void WriteLine(Object value) overload is selected (you can see it if you Ctrl+Click on WriteLine in Visual Studio). This method simply calls the TextWriter.WriteLine(value) 方法,它可以:

IFormattable f = value as IFormattable;
if (f != null)
    WriteLine(f.ToString(null, FormatProvider));
else
    WriteLine(value.ToString());

使用 ILSpy 并查找 Console.WriteLine.

可以很容易地看到所有这些