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

С#: соединение между IFormattable, IFormatProvider и ICustomFormatter, а также когда использовать

В чем разница и связь между IFormattable, IFormatProvider и ICustomFormatter и когда они будут использоваться? Простой пример реализации тоже будет очень приятным.

И я не имею в виду, когда он используется в .NET Framework, но когда я буду реализовывать их самостоятельно, и в этом случае, какие классы обычно реализуют какой интерфейс и как это сделать правильно.

4b9b3361

Ответ 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")

Ответ 2

IFormattable - это объект, который поддерживает разные (именованные/пользовательские) форматы - например, числа и т.д. Используя интерфейс, несколько блоков кода могут использовать значение и строку формата, и это обычно (например) в привязке данных и 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