IFormattable
jest obiektem, który obsługuje formaty w string.Format
, tj xxx
w {0:xxx}
. string.Format
będzie delegować do metody obiektu IFormattable.ToString
, jeśli obiekt obsługuje interfejs.
IFormatProvider
to źródło informacji konfiguracyjnych, które są przydatne w takich formułkach, jak układ daty i waluty zależny od kultury.
Jednak w sytuacjach takich jak np. DateTime
, gdzie instancja, którą chcesz sformatować, już implementuje IFormattable
, ale nie kontrolujesz implementacji (DateTime
jest dostarczany w BCL, nie można go łatwo zastąpić), istnieje mechanizm, który zapobiega używaniu string.Format
po prostu przy użyciu IFormattable.ToString
. Zamiast tego implementujesz IFormatProvider
, a gdy zostaniesz zapytany o implementację ICustomFormatter
, zwróć jeden. string.Format
sprawdza dostawcę pod kątem ICustomFormatter
, zanim przekaże go do obiektu IFormattable.Format
, co z kolei prawdopodobnie poprosi o IFormatProvider
dla danych specyficznych dla kultury, takich jak CultureInfo
.
Oto program, który pokazuje, co string.Format
prosi IFormatProvider
dla i jak przepływ sterowania idzie:
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()));
}
}
Drukuje to:
Asked for System.ICustomFormatter
ToString("foobar", provider) called
arbitrary value
Jeśli dostawca Format zostanie zmieniony w celu zwrócenia niestandardowego formatyzatora, przejmie:
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);
}
}
Kiedy run:
Asked for System.ICustomFormatter
(format was "foobar")
Dlaczego zwracasz 'CultureInfo.CurrentCulture.GetFormat' w' MyFormatProvider.GetFormat'? A co byś użył '' IFormatProvider' dla '' MyCustomFormatter.Format'? – Svish
Domyślnym dostawcą formatu jest CultureInfo.CurrentCulture; to jest ten, który jest używany, jeśli nie określisz jednego z przeciążeń do 'string.Format'. Już wyjaśniłem, do czego użyłbyś IFormatProvider - aby podać informacje o konfiguracji (np. Poprosić o CultureInfo), o takie rzeczy jak formatowanie daty (np. Użycie CultureInfo.DateTimeFormat). –