自定义格式字符串
更新:2007 年 11 月
.NET Framework 支持扩展其内置的格式化机制,这样,您可以自己创建接受用户定义的格式字符串的 ToString 方法,也可以创建格式提供程序来调用您自己的 Format 方法以执行类型的自定义格式化。您可以通过实现 IFormattable 接口来创建自己的 ToString 方法,还可以通过实现 ICustomFormatter 和 IFormatProvider 接口来创建自己的 Format 方法。
本节的信息局限于向用户定义类型和现有基类型添加自定义格式字符串,但所描述的原则可以应用到任何类型。
添加自定义类型的自定义格式字符串
如果要创建自己的自定义类型,您可以通过实现 IFormattable 接口以及该接口的 ToString 方法来添加对处理您自己的自定义格式字符串的支持。这意味着您可以控制哪些格式字符串会被您的自定义类型识别。实现 IFormattable 接口(而不只是将 ToString 方法添至您的自定义类型)的好处在于:您可以保证 ToString 方法的用户能够使用预定义的调用语法和返回类型。
IFormattable 接口的 ToString 方法带有一个格式字符串参数和一个格式提供程序参数。如果格式字符串参数为空字符串或 null(在 Visual Basic 中为 Nothing),则执行默认的格式化。如果格式提供程序为 null,则使用默认格式提供程序。
如果自定义格式字符串被传递到您的自定义版本的 ToString,则执行适当的格式化;否则调用合适的 .NET Framework 方法来执行标准格式化。
在下面的示例中,MyType 自定义类型实现 IFormattable 接口。如果您创建一个新的 MyType 类实例,并将自定义格式字符串“b”传递给该实例的 ToString 方法,则 Convert.ToString 的重载返回该实例的值的二进制(基 2)字符串表示形式。如果没有传递“b”,该实例将用自己的 ToString 方法格式化它的值;也就是说,用 System.Int32.ToString 方法格式化整数 myValue。
Public Class MyType
Implements IFormattable
' Assign a value for the class.
Private myValue As Integer
' Add a constructor.
Public Sub New(value As Integer)
myValue = value
End Sub
' Write a custom Format method for the type.
Public Overloads Function ToString(format As String, _
fp As IFormatProvider) As String _
Implements IFormattable.ToString
If format.Equals("b") Then
Return Convert.ToString(myValue, 2)
Else
Return myValue.ToString(format, fp)
End If
End Function
End Class
public class MyType : IFormattable
{
// Assign a value for the class.
private int myValue;
// Add a constructor.
public MyType( int value )
{
myValue = value;
}
// Write a custom Format method for the type.
public string ToString(string format, IFormatProvider fp)
{
if (format.Equals ("b"))
{
return Convert.ToString (myValue, 2);
}
else
{
return myValue.ToString(format, fp);
}
}
}
下面的示例说明如何使用 MyType 类和格式字符串“b”。
Dim mtype As New MyType(42)
Dim myString As String = mtype.ToString("b", Nothing)
Dim yourString As String = mtype.ToString("d", Nothing)
Console.WriteLine(myString)
Console.WriteLine(yourString)
' The example produces the following output:
' 101010
' 42
MyType mtype = new MyType(42);
String myString = mtype.ToString("b", null);
String yourString = mtype.ToString("d", null);
Console.WriteLine(myString);
Console.WriteLine(yourString);
// The example produces the following output:
// 101010
// 42
向现有类型添加自定义格式字符串
通过创建实现 ICustomFormatter 和 IFormatProvider 的格式提供程序类,您可以控制如何格式化现有的基类型,以及提供用于格式化的附加代码。
当向基类型的 ToString 方法传递格式提供程序时,基类型使用传递的格式提供程序(而不是默认的格式提供程序)定义它的格式化规则。若要创建自定义格式提供程序,应执行下列操作:
将该类传入将 IFormatProvider 作为参数的方法(如 String.Format)。这样做使 String.Format 可以识别在新格式提供程序类中定义的自定义格式方案。
下面的示例定义了一个添加自定义 Format 方法的类,此方法可以产生一个整数的不同基值。
Public Class MyFormat
Implements IFormatProvider
Implements ICustomFormatter
' String.Format calls this method to get an instance of an
' ICustomFormatter to handle the formatting.
Public Function GetFormat(service As Type) As Object _
Implements IFormatProvider.GetFormat
If service.ToString() = GetType(ICustomFormatter).ToString() Then
Return Me
Else
Return Nothing
End If
End Function
' After String.Format gets the ICustomFormatter, it calls this format
' method on each argument.
Public Function Format(theformat As String, arg As Object, _
provider As IFormatProvider) As String _
Implements ICustomFormatter.Format
If theformat Is Nothing Then
Return String.Format("{0}", arg)
End If
Dim i As Integer = theformat.Length
' If the object to be formatted supports the IFormattable
' interface, pass the format specifier to the
' objects ToString method for formatting.
If Not theformat.StartsWith("B") Then
' If the object to be formatted supports the IFormattable
' interface, pass the format specifier to the
' objects ToString method for formatting.
If TypeOf arg Is IFormattable Then
return CType(arg, IFormattable).ToString(theformat, provider)
' If the object does not support IFormattable,
' call the objects ToString method with no additional
' formatting.
ElseIf (arg Is Nothing) Then
return arg.ToString()
End If
End If
' Uses the format string to
' form the output string.
theformat = theformat.Trim(New Char() {"B"c})
Dim b As Integer = Convert.ToInt32(theformat)
Return Convert.ToString(CInt(arg), b)
End Function
End Class
public class MyFormat : IFormatProvider, ICustomFormatter
{
// String.Format calls this method to get an instance of an
// ICustomFormatter to handle the formatting.
public object GetFormat (Type service)
{
if (service == typeof (ICustomFormatter))
{
return this;
}
else
{
return null;
}
}
// After String.Format gets the ICustomFormatter, it calls this format
// method on each argument.
public string Format(string format, object arg, IFormatProvider provider)
{
if (format == null)
{
return String.Format ("{0}", arg);
}
// If the format is not a defined custom code,
// use the formatting support in ToString.
if (!format.StartsWith("B"))
{
//If the object to be formatted supports the IFormattable
//interface, pass the format specifier to the
//objects ToString method for formatting.
if (arg is IFormattable)
{
return ((IFormattable)arg).ToString(format, provider);
}
//If the object does not support IFormattable,
//call the objects ToString method with no additional
//formatting.
else if (arg != null)
{
return arg.ToString();
}
}
// Uses the format string to
// form the output string.
format = format.Trim (new char [] {'B'});
int b = Convert.ToInt32 (format);
return Convert.ToString ((int)arg, b);
}
}
在下面的示例中,Format 方法使用 MyFormat 中定义的自定义 Format 方法来显示 MyInt 的基 16 表示形式。
Dim myInt As Integer = 42
Dim myString As String = String.Format(New MyFormat(), _
"{0} in the custom B16 format is {1:B16}", _
New Object() {MyInt, MyInt})
Console.WriteLine(myString)
' The example displays the following output:
' 42 in the custom B16 format is 2a
int MyInt = 42;
string myString = String.Format(new MyFormat(),
"{0} in the custom B16 format is {1:B16}",
new object[] {MyInt, MyInt});
Console.WriteLine(myString);
// The example displays the following output:
// 42 in custom B16 format is 2a