Реализация ссылок для IFormattable
Есть ли хорошая эталонная реализация для IFormattable? Я планирую иметь хотя бы один заказ IFormatProvider
для моего объекта, и я хочу убедиться, что проводка правильная для различных возможных наборов параметров, передаваемых в IFormattable.ToString(string, IFormatProvider)
,
Что у меня так далеко:
public class MyDataClass : IFormattable
{
/// <seealso cref="IFormattable.ToString(string, IFormatProvider)"/>
public string ToString(string format, IFormatProvider formatProvider)
{
ICustomFormatter formatter = (ICustomFormatter)formatProvider.GetFormat(typeof(ICustomFormatter));
return formatter.Format(format, this, formatProvider);
}
}
Но кажется, что есть другие потенциальные ситуации, которые должны быть рассмотрены, а именно:
- Если
formatProvider
ноль, я должен отступить кthis.ToString()
? - Если
formatProvider.GetFormat(typeof(ICustomFormatter))
возвращаетсяnull
Есть ли конкретное исключение, которое я должен бросить?
Любые сообщения в блоге / примеры кода / ссылки на MSDN приветствуются.
2 ответа
Похоже, вы неправильно понимаете дизайн инфраструктуры форматирования.NET Framework. ICustomFormatter
никогда не следует ссылаться внутри реализации IFormattable.ToString
, поскольку это вступает в противоречие с намеченной целью этого интерфейса.
IFormattable
Объект должен реализовывать только IFormattable
если он знает, как форматировать себя (в идеале он должен делегировать это другому классу, конечно, но здесь будет намеренное соединение). Объект может знать, как форматировать себя несколькими различными способами, поэтому строка форматирования позволяет выбирать между ними. Даже при том, что может все еще отсутствовать информация, такие вещи, которые зависят от культуры. Поэтому существует второй параметр, который предоставляет такую информацию косвенно.
Тип передан IFormatProvider.GetFormat
предназначен для типа или интерфейса, специфичного для класса IFormatProvider
был предоставлен.
Например, встроенные числовые типы хотят иметь возможность извлекать экземпляр System.Globalization.NumberFormatInfo
, в то время как DateTime
связанные классы хотят иметь возможность получить System.Globalization.DateTimeFormatInfo
,
Внедрение IFormattable
Итак, давайте представим, что мы создаем новый класс самоформатирования. Если он знает только один способ отформатировать себя, он должен просто переопределить object.ToString()
, и больше ничего. Если класс знает более одного способа форматирования, он должен реализовать IFormattable
,
format
параметр
Согласно документации IFormattable.ToString
строка формата "G"
(который представляет общий формат) должен поддерживаться. Рекомендуется, чтобы пустая или пустая строка формата была эквивалентна строке формата "G"
, Точное значение зависит от нас.
formatProvider
параметр
Если нам нужно что-то специфическое для культуры или иначе, мы должны использовать IFormatProvider
параметр. Там будет какой-то тип, который мы запрашиваем с его помощью IFormatProvider.GetFormat
, Если IFormatProvider
является нулем, или если IFormatProvider.GetFormat
возвращает null для типа, который мы хотим, мы должны обратиться к некоторому источнику по умолчанию для этой изменяющейся информации.
Источник по умолчанию не обязательно должен быть статическим. Возможно, что источником по умолчанию может быть пользовательская настройка в приложении, а formatProvider
используется для предварительного просмотра изменений параметров и / или когда для сериализации необходим фиксированный формат.
Также возможно, что форматирование может включать форматирование некоторого подобъекта. В этом случае вы, вероятно, хотите передать IFormatProvider
вниз. MSDN имеет отличный пример реализации IFormattable
это показывает именно этот случай.
Другой ToString
перегрузки
При реализации IFormattable
это важно что Object.ToString()
быть переопределено способом, эквивалентным следующему
public override string ToString()
{
return this.ToString(null, System.Globalization.CultureInfo.CurrentCulture);
}
Это гарантирует, что somestring + yourobject
эквивалентно string.Format("{0}{1}",somestring, yourobject)
, что ваши пользователи будут ожидать, чтобы быть правдой.
Для удобства ваших пользователей вы, вероятно, должны предоставить string ToString(string format)
, Кроме того, если ваш формат по умолчанию имеет какие-либо различные компоненты, которые могут извлечь выгоду из IFormatProvider
Вы также можете предоставить public string ToString(IFormatProvider provider)
,
ICustomFormatter
Так что же нам делать, если мы хотим отформатировать класс, который не знает, как его отформатировать, или мы хотим использовать какой-то формат, не поддерживаемый самим классом. Вот где ICustomFormatter становится актуальным. IFormatProvider
что может обеспечить ICustomFormatter
тип может быть передан как IFormatProvider
параметр в таких методах, как string.Format
а также StringBuilder.AppendFormat
,
Обеспеченный ICustomFormatter
имеет свой Format
метод вызывается для каждого форматирования, string.Format
делает. Если ICustomFormatter
не знаком с используемой строкой формата или не поддерживает этот тип, который просто делегирует IFormattable.ToString
или же Object.ToString
, ICustomFormatter
документация предоставляет список того, что необходимо, если вы форматируете объект, который еще не обеспечивает поддержку форматирования, и что необходимо, если вы просто хотите добавить дополнительный формат к существующему IFormattable
, Также приводится пример добавления дополнительного формата.
Ссылка
На этой странице MSDN представлен большой обзор системы форматирования.NET, а также ссылки на практически все другие соответствующие страницы в MSDN. Это лучшее место для начала практически любого вопроса, связанного с форматированием.
Для таких вопросов хороший источник информации можно найти внутри исходного кода Mono. Вероятно, вы найдете немало вариантов использования этого в коде mscorlib.dll.