【问题标题】:Console.Writeline basicsConsole.Writeline 基础知识
【发布时间】:2015-05-23 14:11:23
【问题描述】:

我对以下代码有疑问:

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

文档说:

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

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

【问题讨论】:

  • 请注意,Visual Studio Debugger 的对象检查器也使用非常相似的机制 (MyClass.toString) 来确定当对象显示为单行时要打印的值。
  • Console.WriteLine() 隐式调用ToString(),因此对于您自己的对象,您必须实现/覆盖ToString() 方法。

标签: c# console.writeline


【解决方案1】:

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

Console.WriteLine 有一个 set of overloads 匹配特定类型(主要是原语)。如果编译器与提供的类型不匹配重载,则它与采用System.Object 的重载匹配(允许您提供单个参数)。如果发生这种情况,它会检查该类型是否实现了IFormattable,如果是,它调用IFormattable.ToString(null, Formatter)。如果没有,它会在您的对象上调用ToStringToString 定义在 System.Object 中,所有对象都继承自它。每个需要自定义表示的对象都会覆盖默认行为,就像 DateTime 所做的那样。

例如,假设您有一个带有Bar 字符串属性的Foo 类,并且您希望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”。

【讨论】:

    【解决方案2】:

    由于Console.WriteLine(DateTime) 没有重载,就像你的情况一样,Console.WriteLine(Object) 重载被调用,this overload calls TextWriter.WriteLine(object) overloadimplemented as

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

    如您所见,此方法检查此对象类型是否实现IFormattable interface。由于Datetime implements this interface,您的f.ToString(null, FormatProvider) 将被调用。从这个方法的documentation第一个参数是:

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

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

    如果 format 为 null 或空字符串 (""),则为标准格式 使用了说明符"G".。

    这意味着,表示将是属于您的CurrentCultureShortDatePatternLongTimePattern 属性的组合

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

    【讨论】:

      【解决方案3】:

      与某些人的想法相反,DateTime.ToString() 不会被调用。在 .NET 中,对象可以有两种方式来“字符串化”自身:覆盖 string Object.ToString() 方法和实现 IFormattable 接口。 DateTime 两者都有。

      现在...当你尝试这样做时

      Console.WriteLine(DateTime.Now);
      

      选择了 void 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 可以轻松查看所有这些内容。

      【讨论】: