此文章在aierong 的http://www.cnblogs.com/aierong/archive/2005/04/26/145617.html 基礎上稍加改動。感謝原作者。
.Net提供了將數值、枚舉或日期時間等數據類型表示爲字符串的方法(依賴於給ToString()方法傳入參數),也提供了(包括自定義解析過程)將字符串表示爲某種類型的方法(類/對象名.Parse(string))。
格式化由格式說明符字符的字符串控制,該字符串指示如何表示基類型值;或者怎樣將一個字符串解釋爲某個類型。
例如,格式說明符指示是否應該用科學記數法來表示格式化的數字;格式字符"C",表示貨幣格式等。(參考附錄表格)
同時.NET Framework還使用區域性設置,以便用適合於特定區域性的形式表示基類型。
我們可以提供自定義的區域性設置,或者使用與當前線程關聯的默認區域性設置。
例如,格式化貨幣類型的時候,區域性設置指定用於貨幣符號;格式化時間時根據區域設置來將一個字符串解釋爲DateTime型(DateTime.ParseExact()方法)。
本文主要介紹字符串格式控制
要是我們想擁有自己定義的格式化,.NET Framework也允許我們定義自己格式化方案和自定義區域性設置。例如:我想格式字符"MyFormat",來說明我自定義的格式,即在字符前加三個***,下文有代碼示例。
關於數字格式字符串,可以參考類
System.Globalization.NumberFormatInfo
關於日期與時間格式字符串,可以參考類
System.Globalization.DateTimeFormatInfo
一個類要想實現格式化字符串輸出需要實現Iformattable接口,先看看IFormattable 接口的原型:
public interface IFormattable
{
// Methods
string ToString(string format, IFormatProvider formatProvider);
}
參數說明:
format: 指定要使用的格式的 String,當爲空引用時,表示使用爲IFormattable實現的類型定義的默認格式。
formatProvider: 用於格式化該值的 IFormatProvider,當爲空引用時,從操作系統的當前區域設置中獲取格式信息的。
一些基本的值類型實現了該接口,例如: Int32 ,UInt32 , DateTime ,Guid ,類Enum。
其中的IFormatProvider
接口的原型
public interface IFormatProvider
{
// Methods
object GetFormat(Type formatType);
}
參數說明:
formatType: 一個對象,它指定要獲取的格式對象的類型
NumberFormatInfo、DateTimeFormatInfo和CultureInfo實現IFormatProvider接口。
NumberFormatInfo: 提供數字格式信息,如用於小數分隔符和千位分隔符的字符,以及貨幣值中貨幣符號的拼寫和位置。
DateTimeFormatInfo: 提供與日期相關和與時間相關的格式信息,如日期模式中月、日和年的位置。
CultureInfo: 包含特定區域性中的默認格式信息,其中包括數字格式信息以及與日期相關和與時間相關的格式信息。
再看看ICustomFormatter
接口的原型:
public interface ICustomFormatter
{
// Methods
string Format(string format, object arg, IFormatProvider formatProvider);
}
參數說明:
format: 包含格式規範的格式字符串。爲空時 ,將使用默認格式規範。
arg: 要格式化的對象。其爲空引用時,引發異常。
formatProvider : 一個IFormatProvider對象,它提供有關當前實例的格式信息。爲空時,則忽略該參數。
代碼示例:格式字符串"MyFormat",在字符前加三個***。
using System;
public class MyClass : System.IFormattable
{
Double d;
public MyClass(Double d)
{
this .d = d;
}
public string ToString(string format, IFormatProvider formatProvider)
{
return (format == "MyFormat" ) ? "***" + d.ToString(formatProvider) : d.ToString(format, formatProvider);
}
}
class Program
{
public static void Main()
{
System.Globalization.CultureInfo culture=null ;
MyClass myClass = new MyClass (5);
// 當 IFormatProvider 爲空時 , 調用的是當前線程關聯的文化信息
Console .WriteLine(" 顯示中國貨幣格式 :{0}" , myClass.ToString("C" , null ));
culture = System.Globalization.CultureInfo .CurrentCulture;
Console .WriteLine(" 顯示當前系統默認貨幣格式 :{0}" , myClass.ToString("C" , culture));
culture = new System.Globalization.CultureInfo ("zh-HK" );
Console .WriteLine(" 顯示香港特別行政區貨幣格式 :{0}" , myClass.ToString("C" , culture));
Console .WriteLine(" 顯示我自己定義的貨幣格式 :{0}" , myClass.ToString("MyFormat" , null ));
Console .ReadLine();
}
}
輸出結果:
顯示中國貨幣格式:¥5.00
顯示當前系統默認貨幣格式:¥5.0
顯示香港特別行政區貨幣格式:HK$
顯示我自己定義的貨幣格式:***5
以上示例中CultureInfo類的對象作爲IFormatProvider類型的參數傳入。自定義中調用了Double對象的ToString方法,因爲Double對象也實現了IFormattable接口。
如果希望自定義格式化能在多個不同類使用,那麼實現我們應該定義一個實現ICustomFormatter接口的類:
public class MyBaseFormat : System.ICustomFormatter , System.IFormatProvider
{
// 如果 format Type 與當前實例類型相同,則爲當前實例,否則爲空引用
public object GetFormat(Type format)
{
if (format == typeof (ICustomFormatter ))
return this ;
return null ;
}
// 實現 Format 方法說明 :
// 如果您的格式方法不支持格式,則確定正在設置格式的對象是否實現 IFormattable 接口。
// 如果實現,請調用該接口的 IFormattable.ToString 方法。
// 否則,調用基礎對象的默認 Object.ToString 方法。
public string Format(string format, object arg, IFormatProvider provider)
{
if (format == null )
{
if (arg is IFormattable )
return ((IFormattable )arg).ToString(format, provider);
return arg.ToString();
}
else
{
if (format == "MyBaseFormat" )
{
return "***" + arg.ToString();
}
else
{
if (arg is IFormattable )
return ((IFormattable )arg).ToString(format, provider);
return arg.ToString();
}
}
}
}
class Program
{
public static void Main()
{
string printString = String .Empty;
int i = 100;
MyBaseFormat myBaseFormat = new MyBaseFormat ();
printString = string .Format(myBaseFormat, " 顯示正常格式 :{0}" , i);
Console .WriteLine(printString);
printString = string .Format(myBaseFormat, " 顯示正常格式 :{0:C}" , i);
Console .WriteLine(printString);
printString = string .Format(myBaseFormat, " 顯示自定義格式 {0:MyBaseFormat}" , i);
Console .WriteLine(printString);
Console .ReadLine();
}
}
輸出如下:
顯示正常格式:100
顯示正常格式:¥100.00
顯示自定義格式***100
總結:
1.如果需要您自己的格式化包含在某個類上,在該類上實現IFormattable接口。
2.如果希望自定義格式化並使它可供多個不同類使用,那麼實現 ICustomFormatter接口。
下面的函數是一個在網上找的的使用IFormattable的例子:
using System;
/// <summary>
/// " 點 " 類的定義。
/// </summary>
public class Point : System.IFormattable
{
/// <summary>
/// 點類的橫縱座標。
/// </summary>
private int m_x, m_y;
public Point(int x, int y)
{
m_x = x;
m_y = y;
}
#region IFormattable 成員
/// <summary>
/// 用於生成格式字符串的函數。
/// </summary>
/// <param name="format"> 格式字符串。 </param>
/// <param name="formatProvider"> 區域格式信息對象。 </param>
/// <returns></returns>
public string ToString(string format, IFormatProvider formatProvider)
{
string retString;
try
{
// 判斷格式字符串。
switch (format.ToUpper())
{
case "G" : // 自定義的通用格式。
retString = string .Format(formatProvider, "({0},{1})" , m_x, m_y);
//" 點 " 對象的字符串格式爲: "( 十進制數字,十進制數字 )" 。
break ;
case "S" : // 自定義的標準格式。
retString = string .Format(formatProvider, "<{0},{1}>" , m_x, m_y);
//" 點 " 對象的字符串格式爲: "< 十進制數字,十進制數字 >" 。
break ;
default : // 自定義的默認格式。
retString = string .Format(formatProvider, "({0:X},{1:X})" , m_x, m_y);
//" 點 " 對象的字符串格式爲: "( 十六進制數字,十六進制數字 )" 。
break ;
}
}
catch (System.NullReferenceException )
{
// 格式字符串爲空,返回通用格式。
retString = string .Format(formatProvider, "({0},{1})" , m_x, m_y);
}
return retString;
}
#endregion
}
/// <summary>
/// Test 的摘要說明。
/// </summary>
public class Test
{
public static void Main()
{
// 定義一個點。
Point p = new Point (13, 10);
// 打印默認格式的點。
Console .WriteLine("{0}" , p);
// 打印標準格式的點。
Console .WriteLine("{0:S}" , p);
/*
* 輸出結果: (13,10)
* <13,10>
*/
Console .ReadLine();
}
}
注意:如果不實現IFormattable接口也可以用string.Format這些方法打印自定義類的對象,但string.Format方法只是調用object.ToString方法將類名打印出來。
下面是string.Format這些方法調用ToString的處理順序:
1.如果要格式化的對象的值是 null,則返回空字符串 ("")。
2.如果要格式化的對象所屬的類實現了 ICustomFormatter 接口,則調用ICustomFormatter.Format 方法。
3.如果前面的ICustomFormatter.Format 方法未調用,並且該類實現了 IFormattable 接口,則調用IFormattable.ToString 方法。
4.如果前面的步驟未格式化類型,則調用該類型的ToString方法(從 Object 類繼承而來)。
然而,只有實現了IFormattable或ICustomFormatter這些接口才能識別我們自己定義的格式字符串,打印出我們想要的結果。
附錄:
C# 格式化數值結果表
字符 |
說明 |
示例 |
輸出 |
C |
貨幣 |
string.Format ("{0:C3}", 2) |
$ 2.000 |
D |
十進制 |
string.Format("{0:D3}", 2) |
002 |
E |
科學計數法 |
string.Format("{0:E}", 1.20E+001) |
1.20E+001 |
G |
常規 |
string.Format("{0:G}", 2) |
2 |
N |
用分號隔開的數字 |
string.Format("{0:N}", 250000) |
250,000.00 |
X |
string.Format("{0:X000}", 12) |
C |
|
string.Format("{0:000.000}", 12.2) |
012.200 |
string.Format() 控制字符串縮進小技巧:
Sample |
Generates |
String.Format("->{1,10}<-", "Hello"); |
-> Hello<- |
String.Format("->{1,-10}<-", "Hello"); |
->Hello <- |