String.Format - как это работает и как реализовать пользовательские форматированные строки

С String.Format() можно форматировать, например, DateTime объекты разными способами. Каждый раз, когда я ищу желаемый формат, мне нужно искать в Интернете. Почти всегда я нахожу пример, который я могу использовать. Например:

String.Format("{0:MM/dd/yyyy}", DateTime.Now);          // "09/05/2012"

Но я не знаю, как это работает и какие классы поддерживают эти "магические" дополнительные строки.

Итак, мои вопросы:

  • Как String.Format сопоставить дополнительную информацию MM/dd/yyyy с результатом строки?
  • Поддерживают ли все объекты Microsoft эту функцию?
    Это где-то зарегистрировано?
  • Можно ли сделать что-то вроде этого:
    String.Format("{0:MyCustomFormat}", new MyOwnClass())

Ответ 1

String.Format соответствует каждому из токенов внутри строки ({0} и т.д.) для соответствующего объекта: http://msdn.microsoft.com/en-us/library/system.string.format.aspx

Дополнительно предоставляется строка формата:

{ index[,alignment][ : formatString] }

Если предоставлен formatString, соответствующий объект должен реализовать IFormattable и, в частности, метод ToString, который принимает formatString и возвращает соответствующую форматированную строку: http://msdn.microsoft.com/en-us/library/system.iformattable.tostring.aspx

Может использоваться также IFormatProvider, который может использоваться для захвата основных стандартов форматирования/значений по умолчанию и т.д. Примеры здесь и здесь.

Итак, ответы на ваши вопросы в порядке:

  • Он использует метод IFormattable interface ToString() для объекта DateTime и передает строку формата MM/dd/yyyy. Это реализация, которая возвращает правильную строку.

  • Любой объект, реализующий IFormattable, поддерживает эту функцию. Вы даже можете написать свой собственный!

  • Да, см. выше.

Ответ 2

С моей точки зрения, вам нужно будет реализовать IFormattable в своем классе для поддержки этого. Тогда есть метод ToString, который принимает параметры, которые вы передаете в String.Format.

Вот пример.

// Define other methods and classes here
public class Sample : IFormattable
{
     public string ToString(string format, IFormatProvider provider)
     {
         return String.Concat("Your custom format was ", format);
     }
}

String.Format("{0:MyCustomFormat}", new Sample())

Ответ 3

  • Проверьте официальные документы MSDN, здесь есть полный список строк формата DateTime: http://msdn.microsoft.com/en-us/library/az4se3k1.aspx. На самом деле существует немало "магических" строк.

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

  • Да, вы можете написать свой собственный, и если у вас есть данные, которые могут быть отформатированы по-разному, вы, вероятно, должны написать собственный форматировщик, выполнив IFormattable, снова просмотрите документы здесь: http://msdn.microsoft.com/en-us/library/system.iformattable.aspx. Это довольно просто, вы просто проверяете предоставленные строки и записываете свои данные на их основе, там нет волшебства за кулисами: -)

Ответ 4

Под обложками String.Format делает что-то следующее,

IFormattable formattable = objectToFormat as IFormattable;
if (formattable != null)
{
    formattable.ToString(objectToFormat);
}
else
{
    objectToFormat.ToString();
}

По всем вопросам,

  • Как String.Format сопоставляет дополнительную информацию MM/dd/yyyy с результатом строки?

    Как указано выше, он просто вызывает IFormattable.ToString(строковый формат, поставщик IFormatProvider). Поставщик часто является тем, что говорит вам, что такое культура вашей системы. Часто null, потому что люди не передают его String.Format(), как это было в вашем случае.

  • Поддерживает ли все объекты Microsoft эту функцию? Является ли это документированным где-нибудь?

    Все, что реализует IFormattable, делает.

  • Можно ли сделать что-то вроде этого: String.Format("{0:MyCustomFormat}, new MyOwnClass())

    По существу, если вы хотите, чтобы ваш собственный объект что-то делал с форматом при условии, что вы реализуете IFormattable.

Существует огромное количество поддерживающих классов и счетчиков, чтобы гарантировать, что строки формата во многом схожи. Подробнее здесь.

Ответ 5

Да, это возможно - он может быть полностью настроен. Посмотрите эту ссылку на документацию о форматировании даты и времени.

Если у вас есть свой собственный объект, вам стоит переопределить метод ToString() и вывести все, что, по вашему мнению, соответствующее представление. После этого вы можете использовать String.Format("{0:MyCustomFormat}", new MyOwnClass()), потому что это неявно вызывает MyOwnClass.ToString()

Ответ 6

Документацию по датам можно найти здесь: http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx

Это должно точно указать, что означают все символы форматирования даты, такие как ММ.

Если вы хотите изменить способ вывода строки для пользовательского класса, вы можете переопределить метод ToString, например:

public class User
{
     public string Name { get; set; }
     public int Age { get; set; }

     public override string ToString()
     {
         return this.Name + " is " + this.Age + " years old.";
     }
}

а затем вы можете просто сделать что-то вроде myUser.ToString() и получить указанный вами результат.

Ответ 7

И чтобы ответить на ваш третий вопрос: это невозможно с этим синтаксисом, но вы можете предоставить экземпляры IFormatProvider и ICustomFormatter для типа, который вы не создали, или реализовать IFormattable внутри вашего типа (хотя, который в основном расширяет ToString).