Подтвердить что ты не робот

Основы Console.Writeline

У меня есть вопрос о следующем коде:

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

Документация гласит:

Записывает текстовое представление указанного массива объектов, за которым следует текущий ограничитель строки, до стандартного потока вывода используя указанную информацию о формате.

Итак, мой вопрос: почему WriteLine знает текстовое представление объекта DateTime? Я имею в виду, если я создаю свой собственный объект из своего собственного класса, как он узнает, как преобразовать значение в текст? И даже больше, как он знает, что такое ценность? Как вы можете определить "значение" объекта?

4b9b3361

Ответ 1

Почему WriteLine знает текстовое представление объекта DateTime? Я имею в виду, если я создаю свой собственный объект из своего собственного класса, как он узнает, как преобразовать значение в текст?

Console.WriteLine имеет набор перегрузок, соответствующий определенным типам (в основном примитивам). Если компилятор не соответствует перегрузке с предоставленным типом, он совпадает с перегрузкой System.Object (при условии, что вы предоставляете один параметр). Если это произойдет, он проверяет, реализует ли тип IFormattable, если он это делает, он вызывает IFormattable.ToString(null, Formatter). Если это не так, оно вызывает ToString на вашем объекте. ToString определяется в System.Object, от которого наследуются все объекты. Каждый объект, который хочет создать настраиваемое представление, переопределяет поведение по умолчанию, например DateTime.

Например, скажем, у вас есть класс Foo со значением строки 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);
}

Уступит "бар".

Ответ 2

Так как нет перегрузки для Console.WriteLine(DateTime), как в вашем случае, перегрузка Console.WriteLine(Object) вызывается и эта перегрузка вызывает TextWriter.WriteLine(object) перегрузка, которая реализована как:

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

Как вы можете видеть, этот метод проверяет, реализует ли этот тип объекта IFormattable interface или нет. Поскольку Datetime реализует этот интерфейс, вызывается ваш f.ToString(null, FormatProvider). Из этого метода documentation первый параметр:

Нулевая ссылка (Nothing в Visual Basic) для использования формата по умолчанию определенный для типа реализации IFormattable.

И из документа DateTime.ToString(String, IFormatProvider):

Если формат имеет значение null или пустую строку ( "), стандартный формат спецификатор "G".

Это означает, что представление будет комбинацией ShortDatePattern и LongTimePattern, принадлежащих вашему CurrentCulture

Если вам нужен специальный формат для вашего пользовательского класса, вы можете переопределить метод .ToString() вашего типа, чтобы изменить его поведение.

Ответ 3

Вопреки мнению некоторых людей, DateTime.ToString() не будет. В .NET объект может иметь два способа "подстроить" себя: переопределить метод string Object.ToString() и реализовать интерфейс IFormattable. DateTime делает оба.

Теперь... Когда вы пытаетесь сделать

Console.WriteLine(DateTime.Now);

выбран void public static void WriteLine(Object value) (вы можете увидеть его, если вы нажмете Ctrl + Click на WriteLine в Visual Studio). Этот метод просто вызывает метод TextWriter.WriteLine(value), который выполняет следующие действия:

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

Все это можно легко увидеть с помощью ILSpy и поиска Console.WriteLine.