Ответ 1
-
IFormattable
- это объект, который поддерживает форматы вstring.Format
, т.е.xxx
в{0:xxx}
.string.Format
передаст объектIFormattable.ToString
, если объект поддерживает интерфейс. -
IFormatProvider
является источником информации о конфигурации, которую formatters используют для таких вещей, как дата и форматы для конкретной культуры. -
Однако для ситуаций, таких как, например,
DateTime
, где экземпляр, который вы хотите отформатировать, уже реализуетIFormattable
, но вы не контролируете реализацию (DateTime
предоставляется в BCL, вы не можете легко его заменить), существует механизм для предотвращенияstring.Format
просто используяIFormattable.ToString
. Вместо этого вы реализуетеIFormatProvider
, а при запросе реализацииICustomFormatter
возвращаете один.string.Format
проверяет поставщика дляICustomFormatter
перед тем, как он делегирует объектIFormattable.Format
, который, скорее всего, попроситIFormatProvider
для данных, относящихся к культуре, таких какCultureInfo
.
Вот программа, которая показывает, что string.Format
запрашивает IFormatProvider
for, и как идет поток управления:
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")