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

Помните интернационализацию!

решения здесь только работают на английский язык. Вещи становятся намного более сложными, если необходимо поддерживать другие языки.

, Например, на "1-м" испанском языке был бы записан как "1.o", "1.a", "1.os" или "1.as" в зависимости от того, является ли вещь, которую Вы считаете, мужской, женской или множественной!

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

36
задан Svish 8 November 2009 в 19:01
поделиться

2 ответа

  • 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")
37
ответ дан 27 November 2019 в 06:13
поделиться

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
1
ответ дан 27 November 2019 в 06:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: