Помните интернационализацию!
решения здесь только работают на английский язык. Вещи становятся намного более сложными, если необходимо поддерживать другие языки.
, Например, на "1-м" испанском языке был бы записан как "1.o", "1.a", "1.os" или "1.as" в зависимости от того, является ли вещь, которую Вы считаете, мужской, женской или множественной!
Поэтому, если Ваше программное обеспечение должно поддерживать различные языки, старайтесь избегать ординалов.
IFormattable
- это объект, который поддерживает форматы в string.Format
, то есть xxx
в {0: xxx}
. string.Format
будет делегировать объектному методу IFormattable.ToString
, если объект поддерживает интерфейс.
IFormatProvider
- это источник информации о конфигурации, который средства форматирования используют для таких вещей, как Дата и формат валюты, зависящие от языка и региональных параметров.
Однако для таких ситуаций, как, например, DateTime
, где экземпляр, который вы хотите отформатировать, уже реализует IFormattable
, но вы не контролируете реализацию ( DateTime
предоставляется в BCL, вы не можете легко заменить его), есть механизм, предотвращающий string.Format
от простого использования IFormattable. ToString
. Вместо этого вы реализуете IFormatProvider
и при запросе реализации ICustomFormatter
возвращаете ее. string.Format
проверяет поставщика на наличие ICustomFormatter
перед тем, как делегировать объект IFormattable.Format
, который, в свою очередь, скорее всего, запросит IFormatProvider
для данных, связанных с языком и региональными параметрами, например CultureInfo
.
Вот программа, которая показывает, что string.Format
запрашивает у IFormatProvider
и как поток управление идет:
using System;
using System.Globalization;
class MyCustomObject : IFormattable
{
public string ToString(string format, IFormatProvider provider)
{
Console.WriteLine("ToString(\"{0}\", provider) called", format);
return "arbitrary value";
}
}
class MyFormatProvider : IFormatProvider
{
public object GetFormat(Type formatType)
{
Console.WriteLine("Asked for {0}", formatType);
return CultureInfo.CurrentCulture.GetFormat(formatType);
}
}
class App
{
static void Main()
{
Console.WriteLine(
string.Format(new MyFormatProvider(), "{0:foobar}",
new MyCustomObject()));
}
}
Он печатает следующее:
Asked for System.ICustomFormatter
ToString("foobar", provider) called
arbitrary value
Если поставщик формата изменяется для возврата пользовательского средства форматирования, он принимает на себя:
class MyFormatProvider : IFormatProvider
{
public object GetFormat(Type formatType)
{
Console.WriteLine("Asked for {0}", formatType);
if (formatType == typeof(ICustomFormatter))
return new MyCustomFormatter();
return CultureInfo.CurrentCulture.GetFormat(formatType);
}
}
class MyCustomFormatter : ICustomFormatter
{
public string Format(string format, object arg, IFormatProvider provider)
{
return string.Format("(format was \"{0}\")", format);
}
}
При запуске:
Asked for System.ICustomFormatter
(format was "foobar")
IFormattable
- это объект, который поддерживает различные (именованные / настраиваемые) форматы, например числа и т. Д. Используя интерфейс, несколько блоков кода могут использовать значение и формат. string, и это часто встречается (например) в привязке данных и string.Format
.
IFormatProvider
заполняет некоторые пробелы, связанные с форматированием, в частности i18n. Чаще всего в качестве поставщика используется CultureInfo
, предоставляющий либо конкретный локальный формат, либо инвариантный язык и региональные параметры.
Насколько мне известно, ICustomFormatter
не имеет отношения и связывает подробнее о сериализации ( BinaryFormatter
). Я мог ошибаться ...
Пример объекта IFormattable
:
IFormattable d = 123.45M;
string s1 = d.ToString("c", CultureInfo.CurrentCulture), // local currency
s2 = d.ToString("c", CultureInfo.InvariantCulture); // invariant currency