ここでは、書式プロバイダ(IFormatProvider)、カスタム書式プロバイダ(ICustomFormatter)の役割と、その実装方法ついて見ていきます。
書式プロバイダ (IFormatProvider)
書式プロバイダ(IFormatProvider)は、 D, G などの書式指定子で指定される書式から、それらに対応する形式の文字列にするためのメソッドを提供するインターフェイスです。 書式プロバイダはToString等の書式化を行うメソッドから参照されます。 明示的に書式プロバイダが指定された場合はそれが用いられ、特に指定されない場合はデフォルトとして現在のスレッドのカルチャ(後述)が書式プロバイダとして使用されます。
書式プロバイダとスレッドのカルチャ
ToString等のメソッドでは、引数にIFormatProviderをとるオーバーロードが用意されています。 これらのメソッドでIFormatProviderを指定した場合はそれが書式プロバイダとして機能し、書式化の際に使用されます。 書式プロバイダを指定しなかった場合は、現在のスレッドのカルチャ(Thread.CurrentThread.CurrentCulture)が提供する書式を使ってフォーマットされます。
CultureInfoなどIFormatProviderを実装するインスタンスを指定してToString等を呼び出すか、ToString等を呼び出す前にThread.CurrentThread.CurrentCultureにCultureInfoを設定しておくことで、特定のカルチャ(ロケール)での書式や独自に定義された書式で値をフォーマットすることが出来ます。
標準の書式指定子に対応する書式や、書式化される際に使用される文字列は、CultureInfoに設定されるNumberFormatInfoやDateTimeFormatInfoに設定されている値を元にして組み立てられます。 これらのクラスでは、月名・曜日名の表記や、桁区切り・小数点・通貨単位などの記号が設定されていて、これらの値を変更する事で書式をカスタマイズすることも出来ます。
なお、'ja'や'en'など言語コードのみを指定して作成したCultureInfo(ニュートラルカルチャのCultureInfo)には書式が設定されないため、書式プロバイダとしては機能しません。 ニュートラルカルチャのCultureInfoを指定するとNotSupportedExceptionがスローされます。
スレッドとカルチャについてはカルチャの基本・種類・カルチャ情報の取得、カルチャと書式の関係やNumberFormatInfoに設定される値などの詳細についてはカルチャと書式・テキスト処理・暦で詳しく解説しています。
カスタム書式プロバイダ (ICustomFormatter)
IFormatProviderインターフェイスとICustomFormatterインターフェイスを実装することで、書式指定子とそれに対応する書式を独自に定義することができます。 ICustomFormatterでは書式指定子から適切な書式の文字列へと変換する処理を実装し、IFormatProviderでは変換を行うフォーマッタを取得するための処理を実装します。
書式化の際にカスタム書式プロバイダがどのように用いられるかを述べると次のようになります。 まず、数値型やDateTime型を書式化する場合、IFormatProviderからNumberFormatInfoやDateTimeFormatInfoを取得しようとします。 それ以外の型の場合や、IFormatProviderからNumberFormatInfoやDateTimeFormatInfoを取得出来なかった場合は、代わりにICustomFormatterを取得しようとします。 この時に適切なICustomFormatterを返すことで、独自に定義した書式で文字列化されることになります。
ICustomFormatterの実装例
以下は、書式指定子に応じて文字列を大文字化・小文字化・タイトルケース化するカスタム書式プロバイダTextFormatProviderを実装する例です。 カスタム書式プロバイダTextFormatProviderでは、次のように定義された書式をサポートします。
書式指定子 | 書式 | フォーマット例 | |
---|---|---|---|
入力文字列 | フォーマット結果 | ||
U, u | 与えられた文字列を大文字化する |
"Hello world"
|
"HELLO WORLD"
|
L, l | 与えられた文字列を小文字化する |
"hello world"
|
|
T, t | 与えられた文字列をタイトルケース化する |
"Hello World"
|
この例で実装しているICustomFormatter.Formatメソッドの動作は次のとおりです。
- 引数が文字列の場合
- 書式指定子が U, u の場合は、引数で指定された文字列を大文字化して返す
- 書式指定子が L, l の場合は、引数で指定された文字列を小文字化して返す
- 書式指定子が T, t の場合は、引数で指定された文字列をタイトルケース化して返す
- 書式指定子が指定されていない場合は、引数で指定された文字列をそのまま返す
- 上記以外の書式指定子の場合、FormatExceptionをスローする
- 引数が文字列以外の場合
- 引数がIFormattableを実装している場合は、IFormattable.ToStringの結果を返す
- 引数がIFormattableを実装していない場合は、Object.ToStringの結果を返す
なお、この例では大文字化・小文字化・タイトルケース化にTextInfoクラスのToUpperメソッド・ToLowerメソッド・ToTitleCaseメソッドを使っています。 TextInfoクラスについてはカルチャと書式・テキスト処理・暦を参照してください。 また、この例で触れているIFormattableインターフェイスについては後ほど解説します。
書式を指定した文字列化のサポート (IFormattable)
クラスや構造体にIFormattableインターフェイスを実装すると、独自に定義した書式で文字列化するToStringメソッドを用意することができます。 int, double, DateTime等の基本型はIFormattableインターフェイスを実装していて、これにより書式を指定して文字列化できるようになっています。 ICustomFormatterでは書式化の実装を書式化したい型とは別のクラスで実装するのに対し、IFormattableでは書式化の実装を書式化したい型自体に実装することができます。
IFormattableの実装例
以下は、複素数型Complexを用意し、IFormattableで書式化処理を実装する例です。 この例では次の書式指定子をサポートします。
書式指定子 | 書式 | フォーマット例 | |
---|---|---|---|
値と書式指定子 | フォーマット結果 | ||
Gn | 精度nのガウス平面座標表示 "(a, b)"の形式 |
(new Complex(4.0, 3.0)).ToString("G")
|
"(4.00, 3.00)"
|
(new Complex(4.0, 3.0)).ToString("G4")
|
"(4.0000, 3.0000)"
|
||
An | 精度nの絶対値表示 |z|の値の形式 |
(new Complex(4.0, 3.0)).ToString("A")
|
"5.00"
|
(new Complex(-4.0, -3.0)).ToString("A4")
|
"5.0000"
|
||
Cn | 精度nの直交座標表示 "a±bi"の形式 (実部または虚部が0の場合は表示しない) |
(new Complex(4.0, 3.0)).ToString("C1")
|
"4.0+3.0i"
|
(new Complex(0.0, -1.0)).ToString("C1")
|
"-1.0i"
|
||
Pn | 精度nの極座標表示 "r∠θ"の形式 |
(new Complex(4.0, 3.0)).ToString("P1")
|
"5.0∠0.2π"
|
(new Complex(1.414, 1.414)).ToString("P3")
|
"2.000∠0.250π"
|
なお、この例では書式指定子で精度nが省略された場合は書式指定子 F のデフォルトの精度で文字列化します。 また、double型の値を書式指定子 F で文字列化する際に、引数で渡されたIFormatProviderを使って書式化するようにしています。 そのため、CultureInfoが渡された場合はそのカルチャでの書式に従って文字列化されます。
.NET Framework 4より導入されているSystem.Numerics.Complex構造体では、このような複数の書式はサポートされていません。
System.Numerics.Complex構造体については、複素数型で詳しく解説しています。