ここでは、書式プロバイダ(IFormatProvider)、カスタム書式プロバイダ(ICustomFormatter)の役割と、その実装方法ついて見ていきます。
書式プロバイダ (IFormatProvider)
書式プロバイダ(IFormatProvider)は、 D, G などの書式指定子で指定される書式から、それらに対応する形式の文字列にするためのメソッドを提供するインターフェイスです。 書式プロバイダはToString等の書式化を行うメソッドから参照されます。 明示的に書式プロバイダが指定された場合はそれが用いられ、特に指定されない場合はデフォルトとして現在のスレッドのカルチャ(後述)が書式プロバイダとして使用されます。
書式プロバイダとスレッドのカルチャ
ToString等のメソッドでは、引数にIFormatProviderをとるオーバーロードが用意されています。 これらのメソッドでIFormatProviderを指定した場合はそれが書式プロバイダとして機能し、書式化の際に使用されます。 書式プロバイダを指定しなかった場合は、現在のスレッドのカルチャ(Thread.CurrentThread.CurrentCulture)が提供する書式を使ってフォーマットされます。
CultureInfoなどIFormatProviderを実装するインスタンスを指定してToString等を呼び出すか、ToString等を呼び出す前にThread.CurrentThread.CurrentCultureにCultureInfoを設定しておくことで、特定のカルチャ(ロケール)での書式や独自に定義された書式で値をフォーマットすることが出来ます。
using System;
using System.Threading;
using System.Globalization;
class Sample {
static void Main()
{
DateTime dt = new DateTime(2010, 9, 14, 1, 2, 3, 456);
// IFormatProviderを指定しない場合
// (現在のスレッドのカルチャ'ja-JP'での書式でフォーマットされる)
Console.WriteLine("{0} {1:U}", Thread.CurrentThread.CurrentCulture, dt);
// Thread.CurrentThread.CurrentCultureに'en-US'のCultureInfoを指定した場合
// (現在のスレッドのカルチャ'en-US'での書式でフォーマットされる)
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
Console.WriteLine("{0} {1:U}", Thread.CurrentThread.CurrentCulture, dt);
// Thread.CurrentThread.CurrentCultureに'es-ES'のCultureInfoを指定した場合
// (現在のスレッドのカルチャ'es-ES'での書式でフォーマットされる)
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("es-ES");
Console.WriteLine("{0} {1:U}", Thread.CurrentThread.CurrentCulture, dt);
// ToStringメソッドでIFormatProviderを指定した場合
// (引数で指定したIFormatProvider=カルチャ'ja-JP'での書式でフォーマットされる)
Console.WriteLine("{0} {1}", Thread.CurrentThread.CurrentCulture, dt.ToString("U", CultureInfo.GetCultureInfo("ja-JP")));
// String.FormatメソッドでIFormatProviderを指定した場合
// (上と同様、引数で指定したIFormatProvider=カルチャ'ja-JP'での書式でフォーマットされる)
Console.WriteLine(String.Format(CultureInfo.GetCultureInfo("ja-JP"), "{0} {1:U}", Thread.CurrentThread.CurrentCulture, dt));
}
}
Imports System
Imports System.Globalization
Imports System.Threading
Class Sample
Shared Sub Main()
Dim dt As New DateTime(2010, 9, 14, 1, 2, 3, 456)
' IFormatProviderを指定しない場合
' (現在のスレッドのカルチャ'ja-JP'での書式でフォーマットされる)
Console.WriteLine("{0} {1:U}", Thread.CurrentThread.CurrentCulture, dt)
' Thread.CurrentThread.CurrentCultureに'en-US'のCultureInfoを指定した場合
' (現在のスレッドのカルチャ'en-US'での書式でフォーマットされる)
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US")
Console.WriteLine("{0} {1:U}", Thread.CurrentThread.CurrentCulture, dt)
' Thread.CurrentThread.CurrentCultureに'es-ES'のCultureInfoを指定した場合
' (現在のスレッドのカルチャ'es-ES'での書式でフォーマットされる)
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("es-ES")
Console.WriteLine("{0} {1:U}", Thread.CurrentThread.CurrentCulture, dt)
' ToStringメソッドでIFormatProviderを指定した場合
' (引数で指定したIFormatProvider=カルチャ'ja-JP'での書式でフォーマットされる)
Console.WriteLine("{0} {1}", Thread.CurrentThread.CurrentCulture, dt.ToString("U", CultureInfo.GetCultureInfo("ja-JP")))
' String.FormatメソッドでIFormatProviderを指定した場合
' (上と同様、引数で指定したIFormatProvider=カルチャ'ja-JP'での書式でフォーマットされる)
Console.WriteLine(String.Format(CultureInfo.GetCultureInfo("ja-JP"), "{0} {1:U}", Thread.CurrentThread.CurrentCulture, dt))
End Sub
End Class
ja-JP 2010年9月13日 16:02:03 en-US Monday, September 13, 2010 4:02:03 PM es-ES lunes, 13 de septiembre de 2010 16:02:03 es-ES 2010年9月13日 16:02:03 es-ES 2010年9月13日 16:02:03
標準の書式指定子に対応する書式や、書式化される際に使用される文字列は、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インターフェイスについては後ほど解説します。
using System;
using System.Globalization;
class TextFormatProvider : IFormatProvider, ICustomFormatter {
// IFormatProvider.GetFormatの明示的な実装
object IFormatProvider.GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
// IFormatProviderにICustomFormatter型を要求された場合は自分自身を返す
return this;
else
// それ以外の場合はnullを返す
return null;
}
// ICustomFormatter.Formatの実装
public string Format(string format, object arg, IFormatProvider formatProvider)
{
string argString = arg as string;
if (argString != null) {
// 引数がstring型の場合、指定された書式に合わせて文字列化する
switch (format) {
case "u":
case "U": // 書式指定子が"U"または"u"の時は、すべて大文字にする
return CultureInfo.CurrentCulture.TextInfo.ToUpper(argString);
case "l":
case "L": // 書式指定子が"L"または"l"の時は、すべて小文字にする
return CultureInfo.CurrentCulture.TextInfo.ToLower(argString);
case "t":
case "T": // 書式指定子が"T"または"t"の時は、タイトルケースにする
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(argString);
default:
if (string.IsNullOrEmpty(format))
// 書式指定子が指定されていない場合は、そのままにする
return argString;
else
// それ以外の書式指定子の場合は、FormatExceptionをスローする
throw new FormatException(string.Format("'{0}'は不正な書式指定子です", format));
}
}
// 引数がString型でない場合
if (arg is IFormattable)
// 引数がIFormattableを実装している場合は、IFormattable.ToStringメソッドで文字列化する
return ((IFormattable)arg).ToString(format, formatProvider);
else
// 引数がIFormattableを実装していない場合は、Object.ToStringメソッドで文字列化する
return arg.ToString();
}
}
class Sample {
static void Main()
{
IFormatProvider fp = new TextFormatProvider();
// 文字列を書式化
Console.WriteLine(string.Format(fp, "{0} {0:U} {0:u} {0:L} {0:l} {0:T} {0:t}", "HoGe"));
Console.WriteLine();
string text = "The quick brown fox jumps over the lazy dog";
Console.WriteLine(string.Format(fp, "{0}", text));
Console.WriteLine(string.Format(fp, "{0:U}", text));
Console.WriteLine(string.Format(fp, "{0:L}", text));
Console.WriteLine(string.Format(fp, "{0:T}", text));
Console.WriteLine();
// int型の値を書式化
int intValue = 42;
Console.WriteLine(string.Format(fp, "{0:D4} {0:F2}", intValue));
Console.WriteLine(intValue.ToString("X8", fp));
Console.WriteLine();
// DateTime型の値を書式化
DateTime dateTimeValue = new DateTime(2010, 9, 14, 1, 2, 3);
Console.WriteLine(string.Format(fp, "{0:u} {0:s}", dateTimeValue));
Console.WriteLine(dateTimeValue.ToString("r", fp));
Console.WriteLine();
// 不正な書式を指定
try {
Console.WriteLine(string.Format(fp, "{0:U} {0:X}", "HoGe"));
}
catch (FormatException ex) {
Console.Error.WriteLine(ex.Message);
}
}
}
Imports System
Imports System.Globalization
Class TextFormatProvider
Implements IFormatProvider, ICustomFormatter
' IFormatProvider.GetFormatの実装
Private Function GetFormat(ByVal formatType As Type) As Object Implements IFormatProvider.GetFormat
If GetType(ICustomFormatter).Equals(formatType) Then
' IFormatProviderにICustomFormatter型を要求された場合は自分自身を返す
Return Me
Else
' それ以外の場合はNothingを返す
Return Nothing
End If
End Function
' ICustomFormatter.Formatの実装
Public Function Format(ByVal format As String, ByVal arg As Object, ByVal formatProvider As IFormatProvider) As String Implements ICustomFormatter.Format
Dim argString As String = TryCast(arg, String)
If argString IsNot Nothing Then
' 引数がstring型の場合、指定された書式に合わせて文字列化する
Select Case format
Case "u", "U" ' 書式指定子が"U"または"u"の時は、すべて大文字にする
Return CultureInfo.CurrentCulture.TextInfo.ToUpper(argString)
Case "l", "L" ' 書式指定子が"L"または"l"の時は、すべて小文字にする
Return CultureInfo.CurrentCulture.TextInfo.ToLower(argString)
Case "t", "T" ' 書式指定子が"T"または"t"の時は、タイトルケースにする
Return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(argString)
Case Else
If String.IsNullOrEmpty(format) Then
' 書式指定子が指定されていない場合は、そのままにする
Return argString
Else
' それ以外の書式指定子の場合は、FormatExceptionをスローする
Throw New FormatException(string.Format("'{0}'は不正な書式指定子です", format))
End If
End Select
End If
' 引数がString型でない場合
If TypeOf arg Is IFormattable Then
' 引数がIFormattableを実装している場合は、IFormattable.ToStringメソッドで文字列化する
Return CType(arg, IFormattable).ToString(format, formatProvider)
Else
' 引数がIFormattableを実装していない場合は、Object.ToStringメソッドで文字列化する
Return arg.ToString()
End If
End Function
End Class
Class Sample
Shared Sub Main()
Dim fp As New TextFormatProvider()
' 文字列を書式化
Console.WriteLine(String.Format(fp, "{0} {0:U} {0:u} {0:L} {0:l} {0:T} {0:t}", "HoGe"))
Console.WriteLine()
Dim text As String = "The quick brown fox jumps over the lazy dog"
Console.WriteLine(String.Format(fp, "{0}", text))
Console.WriteLine(String.Format(fp, "{0:U}", text))
Console.WriteLine(String.Format(fp, "{0:L}", text))
Console.WriteLine(String.Format(fp, "{0:T}", text))
Console.WriteLine()
' Integer型の値を書式化
Dim intValue As Integer = 42
Console.WriteLine(String.Format(fp, "{0:D4} {0:F2}", intValue))
Console.WriteLine(intValue.ToString("X8", fp))
Console.WriteLine()
' DateTime型の値を書式化
Dim dateTimeValue As New DateTime(2010, 9, 14, 1, 2, 3)
Console.WriteLine(String.Format(fp, "{0:u} {0:s}", dateTimeValue))
Console.WriteLine(dateTimeValue.ToString("r", fp))
Console.WriteLine()
' 不正な書式を指定
Try
Console.WriteLine(String.Format(fp, "{0:U} {0:X}", "HoGe"))
Catch ex As FormatException
Console.Error.WriteLine(ex.Message)
End Try
End Sub
End Class
HoGe HOGE HOGE hoge hoge Hoge Hoge The quick brown fox jumps over the lazy dog THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG the quick brown fox jumps over the lazy dog The Quick Brown Fox Jumps Over The Lazy Dog 0042 42.00 0000002A 2010-09-14 01:02:03Z 2010-09-14T01:02:03 Tue, 14 Sep 2010 01:02:03 GMT 'X'は不正な書式指定子です
書式を指定した文字列化のサポート (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が渡された場合はそのカルチャでの書式に従って文字列化されます。
using System;
using System.Globalization;
struct Complex : IFormattable {
public double Real; // 実部
public double Imaginary; // 虚部
public Complex(double real, double imaginary)
: this()
{
this.Real = real;
this.Imaginary = imaginary;
}
// Object.ToStringのオーバーライド
public override string ToString()
{
// 書式と書式プロバイダを指定せずにToStringを呼ぶ
return ToString(null, null);
}
public string ToString(string format)
{
// 書式プロバイダを指定せずにToStringを呼ぶ
return ToString(format, null);
}
// IFormattable.ToString(string, IFormatProvider)の実装
public string ToString(string format, IFormatProvider formatProvider)
{
if (string.IsNullOrEmpty(format)) format = "G"; // 指定されていない場合は"G"の書式を使用
char f = format[0]; // 書式指定文字列の1文字目で書式の種類を分ける
string acc = format.Substring(1); // 書式指定文字列の2文字目以降を精度として扱う
switch (f) {
case 'G': // ガウス平面座標表示
return string.Format(formatProvider, "({0:F" + acc + "}, {1:F" + acc + "})", Real, Imaginary);
case 'A': // 絶対値表示
return Math.Sqrt(Real * Real + Imaginary * Imaginary).ToString("F" + acc, formatProvider);
case 'C': // 直交形式表示
{
// 実部の値が0の場合は表示しない
string realPart = (Real == 0.0) ? null : Real.ToString("F" + acc, formatProvider);
string imaginaryPart;
string sign;
if (Imaginary == 0.0) {
// 虚部の値が0の場合は表示しない
imaginaryPart = null;
sign = null;
}
else if (0.0 < Imaginary) {
imaginaryPart = Imaginary.ToString("F" + acc, formatProvider) + "i";
sign = (realPart == null) ? null : "+"; // 実部を表示する場合のみ符号を付ける
}
else /*if (Imaginary < 0.0)*/ {
imaginaryPart = (-Imaginary).ToString("F" + acc, formatProvider) + "i";
sign = "-";
}
return string.Concat(realPart, sign, imaginaryPart);
}
case 'P': // 極形式表示
{
double r = Math.Sqrt(Real * Real + Imaginary * Imaginary);
double t = Math.Atan2(Imaginary, Real) / Math.PI;
return string.Format(formatProvider, "{0:F" + acc + "}∠{1:F" + acc + "}π", r, t);
}
default:
throw new FormatException(string.Format("'{0}'は不正な書式指定子です", format));
}
}
}
class Sample {
static void Main()
{
Console.WriteLine("{0}, {0:G}, {0:A}, {0:C1}, {0:P6}", (new Complex(4.0, 3.0)));
Console.WriteLine();
Console.WriteLine((new Complex( 3.000, 4.000)).ToString());
Console.WriteLine((new Complex( 1.414, 1.414)).ToString());
Console.WriteLine((new Complex( 3.000, 4.000)).ToString("G", CultureInfo.GetCultureInfo("ja-JP")));
Console.WriteLine((new Complex(-1.414, 1.414)).ToString("G4", CultureInfo.GetCultureInfo("en-US")));
Console.WriteLine((new Complex( 0.000, 1.000)).ToString("G12", CultureInfo.GetCultureInfo("fr-FR")));
Console.WriteLine();
Console.WriteLine((new Complex( 3.000, 4.000)).ToString("A"));
Console.WriteLine((new Complex(-4.000, -3.000)).ToString("A4", CultureInfo.GetCultureInfo("ja-JP")));
Console.WriteLine((new Complex( 1.000, -1.000)).ToString("A1", CultureInfo.GetCultureInfo("en-US")));
Console.WriteLine((new Complex( 2.000, 0.000)).ToString("A1", CultureInfo.GetCultureInfo("fr-FR")));
Console.WriteLine();
Console.WriteLine((new Complex( 3.000, 4.000)).ToString("C"));
Console.WriteLine((new Complex(-0.707, 0.707)).ToString("C2"));
Console.WriteLine((new Complex( 0.707, -0.707)).ToString("C2"));
Console.WriteLine((new Complex( 1.000, 0.000)).ToString("C1"));
Console.WriteLine((new Complex(-1.000, 0.000)).ToString("C1", CultureInfo.GetCultureInfo("ja-JP")));
Console.WriteLine((new Complex( 0.000, 1.000)).ToString("C1", CultureInfo.GetCultureInfo("en-US")));
Console.WriteLine((new Complex( 0.000, -1.000)).ToString("C1", CultureInfo.GetCultureInfo("fr-FR")));
Console.WriteLine((new Complex( 1.000, 1.000)).ToString("C1"));
Console.WriteLine((new Complex( 1.000, -1.000)).ToString("C1"));
Console.WriteLine();
Console.WriteLine((new Complex( 1.000, 0.000)).ToString("P3"));
Console.WriteLine((new Complex( 1.414, 1.414)).ToString("P3"));
Console.WriteLine((new Complex( 0.000, 1.000)).ToString("P3", CultureInfo.GetCultureInfo("ja-JP")));
Console.WriteLine((new Complex(-1.000, 0.000)).ToString("P3", CultureInfo.GetCultureInfo("en-US")));
Console.WriteLine((new Complex( 0.000, -1.000)).ToString("P3", CultureInfo.GetCultureInfo("fr-FR")));
Console.WriteLine((new Complex( 0.000, 0.000)).ToString("P3"));
Console.WriteLine((new Complex(-3.000, 4.000)).ToString("P3"));
}
}
Imports System
Imports System.Globalization
Structure Complex
Implements IFormattable
Public Real As Double ' 実部
Public Imaginary As Double ' 虚部
Public Sub New(ByVal real As Double, ByVal imaginary As Double)
MyClass.Real = real
MyClass.Imaginary = imaginary
End Sub
' Object.ToStringのオーバーライド
Public Overrides Function ToString() As String
' 書式と書式プロバイダを指定せずにToStringを呼ぶ
Return ToString(Nothing, Nothing)
End Function
Public Function ToString(ByVal format As String) As String
' 書式プロバイダを指定せずにToStringを呼ぶ
Return ToString(format, Nothing)
End Function
' IFormattable.ToString(string, IFormatProvider)の実装
Public Function ToString(ByVal format As String, ByVal formatProvider As IFormatProvider) As String Implements IFormattable.ToString
If String.IsNullOrEmpty(format) Then format = "G" ' 指定されていない場合は"G"の書式を使用
Dim f As Char = format(0) ' 書式指定文字列の1文字目で書式の種類を分ける
Dim acc As String = format.Substring(1) ' 書式指定文字列の2文字目以降を精度として扱う
Select Case f
Case "G"c ' ガウス平面座標表示
Return String.Format(formatProvider, "({0:F" + acc + "}, {1:F" + acc + "})", Real, Imaginary)
Case "A"c ' 絶対値表示
Return Math.Sqrt(Real * Real + Imaginary * Imaginary).ToString("F" + acc, formatProvider)
Case "C"c ' 直交形式表示
' 実部の値が0の場合は表示しない
Dim realPart As String = If (Real = 0.0, Nothing, Real.ToString("F" + acc, formatProvider))
Dim imaginaryPart As String
Dim sign As String
If Imaginary = 0.0
' 虚部の値が0の場合は表示しない
imaginaryPart = Nothing
sign = Nothing
Else If 0.0 < Imaginary
imaginaryPart = Imaginary.ToString("F" + acc, formatProvider) + "i"
sign = If(realPart Is Nothing, Nothing, "+") ' 実部を表示する場合のみ符号を付ける
Else ' If Imaginary < 0.0
imaginaryPart = (-Imaginary).ToString("F" + acc, formatProvider) + "i"
sign = "-"
End If
Return String.Concat(realPart, sign, imaginaryPart)
Case "P"c: ' 極形式表示
Dim r As Double = Math.Sqrt(Real * Real + Imaginary * Imaginary)
Dim t As Double = Math.Atan2(Imaginary, Real) / Math.PI
Return String.Format(formatProvider, "{0:F" + acc + "}∠{1:F" + acc + "}π", r, t)
Case Else
Throw New FormatException(String.Format("'{0}'は不正な書式指定子です", format))
End Select
End Function
End Structure
Class Sample
Shared Sub Main()
Console.WriteLine("{0}, {0:G}, {0:A}, {0:C1}, {0:P6}", (New Complex(4.0, 3.0)))
Console.WriteLine()
Console.WriteLine((New Complex( 3.000, 4.000)).ToString())
Console.WriteLine((New Complex( 1.414, 1.414)).ToString())
Console.WriteLine((New Complex( 3.000, 4.000)).ToString("G", CultureInfo.GetCultureInfo("ja-JP")))
Console.WriteLine((New Complex(-1.414, 1.414)).ToString("G4", CultureInfo.GetCultureInfo("en-US")))
Console.WriteLine((New Complex( 0.000, 1.000)).ToString("G12", CultureInfo.GetCultureInfo("fr-FR")))
Console.WriteLine()
Console.WriteLine((New Complex( 3.000, 4.000)).ToString("A"))
Console.WriteLine((New Complex(-4.000, -3.000)).ToString("A4", CultureInfo.GetCultureInfo("ja-JP")))
Console.WriteLine((New Complex( 1.000, -1.000)).ToString("A1", CultureInfo.GetCultureInfo("en-US")))
Console.WriteLine((New Complex( 2.000, 0.000)).ToString("A1", CultureInfo.GetCultureInfo("fr-FR")))
Console.WriteLine()
Console.WriteLine((New Complex( 3.000, 4.000)).ToString("C"))
Console.WriteLine((New Complex(-0.707, 0.707)).ToString("C2"))
Console.WriteLine((New Complex( 0.707, -0.707)).ToString("C2"))
Console.WriteLine((New Complex( 1.000, 0.000)).ToString("C1"))
Console.WriteLine((New Complex(-1.000, 0.000)).ToString("C1", CultureInfo.GetCultureInfo("ja-JP")))
Console.WriteLine((New Complex( 0.000, 1.000)).ToString("C1", CultureInfo.GetCultureInfo("en-US")))
Console.WriteLine((New Complex( 0.000, -1.000)).ToString("C1", CultureInfo.GetCultureInfo("fr-FR")))
Console.WriteLine((New Complex( 1.000, 1.000)).ToString("C1"))
Console.WriteLine((New Complex( 1.000, -1.000)).ToString("C1"))
Console.WriteLine()
Console.WriteLine((New Complex( 1.000, 0.000)).ToString("P3"))
Console.WriteLine((New Complex( 1.414, 1.414)).ToString("P3"))
Console.WriteLine((New Complex( 0.000, 1.000)).ToString("P3", CultureInfo.GetCultureInfo("ja-JP")))
Console.WriteLine((New Complex(-1.000, 0.000)).ToString("P3", CultureInfo.GetCultureInfo("en-US")))
Console.WriteLine((New Complex( 0.000, -1.000)).ToString("P3", CultureInfo.GetCultureInfo("fr-FR")))
Console.WriteLine((New Complex( 0.000, 0.000)).ToString("P3"))
Console.WriteLine((New Complex(-3.000, 4.000)).ToString("P3"))
End Sub
End Class
(4.00, 3.00), (4.00, 3.00), 5.00, 4.0+3.0i, 5.000000∠0.204833π (3.00, 4.00) (1.41, 1.41) (3.00, 4.00) (-1.4140, 1.4140) (0,000000000000, 1,000000000000) 5.00 5.0000 1.4 2,0 3.00+4.00i -0.71+0.71i 0.71-0.71i 1.0 -1.0 1.0i -1,0i 1.0+1.0i 1.0-1.0i 1.000∠0.000π 2.000∠0.250π 1.000∠0.500π 1.000∠1.000π 1,000∠-0,500π 0.000∠0.000π 5.000∠0.705π
.NET Framework 4より導入されているSystem.Numerics.Complex構造体では、このような複数の書式はサポートされていません。
System.Numerics.Complex構造体については、複素数型で詳しく解説しています。