大家好,今天我将為大家介紹 C# 中如何自定義格式化字元串說明符。
程式設計時候經常會用到 Console.WriteLine() 這個函數,其中必不可少的就是各種各樣的格式化說明符,他們負責将要輸出的字元串以各種形式輸出。但畢竟 C# 中定義好的格式化說明符有限,不能滿足所有人的需求,是以,自定義格式化說明符就顯得有必要了。
在學習之前,有必要先了解一下 Console.WriteLine() 函數的工作方式。
實際上,Console.WriteLine() 函數會将其所有的參數傳遞給靜态方法 String.Format() ,然後由該函數進行格式說明符的轉換。
String.Format() 形式如下:
string.Format(this.FormatProvider ,format ,neW object[](argO ,arg1....))
示例:
Console.WriteLine("hello world {0:E}", 123);
運作結果為:hello world 1.230000E+002
因為 "E" 表示以科學計數法表示 123 這個數而且結果的 "E" 大寫。而 Console.WriteLine() 将所有參數(此例中為兩個)傳遞給 String.Format() 方法, 該方法負責把格式化說明符轉換為相應的格式,進而構造出最終的結果。
但構造的過程不是建立一個 String 類的執行個體,而是一個 StringBuilder 類的執行個體(因為這個過程需要不斷改寫這個字元串執行個體,而 String 是不可變類型,每次改變都要創造一個新的字元串,會有額外的消耗,是以用 StringBuilder 類的執行個體,該類是專門應對需要更改字元串的情況的,詳情請參閱 MSDN)。
在構造的過程中,會先建立一個 StringBuilder 執行個體,并初始化為 "hello world"(實際上是初始化到第一個花括号前),然後不斷調用靜态方法 StringBuilder.Append() 和 StringBuilder.AppendFormat() 。前者負責花括号之前的字元串添加,後者負責對花括号的内容進行轉換。
而 StringBuilder.AppendFormat() 方法執行時會先檢查存儲值的對象是否實作 IFormattable 接口,如果實作了該接口,則會調用該接口提供的具有2個參數的方法 ToString() 。該接口定義如下:
interface IFormattable
{
string ToString(string format,IFormatProvider formatProvider)
}
其中 format 就是格式化說明符,而 formatProvider 主要是用于提供背景文化資訊,如果為空,則是系統預設的背景文化資訊,此處不深究。
内置的類型都實作這個接口,可以對字元串進行格式化,如果是自己定義的類(結構體也可),則需要實作這個接口,才可以進行格式化,若不實作這個接口,則隻能調用對象本身的 ToString() 方法。
最後,ToString() 方法會傳回一個字元串,代替原來的花括号内容。
下面用一個坐标示例來示範:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StringFormat
{
class Program
{
static void Main(string[] args)
{
//開始測試,類定義在下面
Vector v = new Vector(3, 2, 4);
Console.WriteLine("以 xI+yJ+zK 的格式顯示");
Console.WriteLine("{0:V}", v);
Console.WriteLine("以 xi+yj+zk 的格式顯示");
Console.WriteLine("{0:v}", v);
Console.WriteLine("以數字形式顯示");
Console.WriteLine("{0:N}", v);
Console.WriteLine("以數字形式顯示");
Console.WriteLine("{0:n}", v);
Console.WriteLine("以大寫 E 科學計數法顯示");
Console.WriteLine("{0:EE}", v);
Console.WriteLine("以小寫 e 科學計數法顯示");
Console.WriteLine("{0:ee}", v);
Console.WriteLine("對象預設的 ToStrin() 方法顯示");
Console.WriteLine("{0:a}", v);
Console.ReadKey();
}
}
//定義Vector類,實作IFomattable接口
class Vector:IFormattable
{
double x, y, z; //定義三個坐标
//構造函數
public Vector(double x, double y, double z)
{
this.x = x;
this.y = y;
this.z = z;
}
//實作帶有兩個參數的ToString()方法
public String ToString(String format, IFormatProvider formatProvide)
{
//根據format的值決定如何顯示
switch (format)
{
//以 xI+yJ+zK 的格式顯示
case "V":
StringBuilder sbV = new StringBuilder(x.ToString(), 30);
sbV.Append("I + ");
sbV.Append(y.ToString());
sbV.Append("J + ");
sbV.Append(z.ToString());
sbV.Append("K");
return sbV.ToString();
//以 xi+yj+zk 的格式顯示
case "v":
StringBuilder sbv = new StringBuilder(this.x.ToString(), 30);
sbv.Append("i + ");
sbv.Append(this.y.ToString());
sbv.Append("j + ");
sbv.Append(this.z.ToString());
sbv.Append("k");
return sbv.ToString();
//以數字形式顯示
case "N":
case "n":
return String.Format("({0} ,{1}, {2})", x, y, z);
//以大寫 E 科學計數法顯示
case "EE":
return String.Format("{0:E} ,{1:E} ,{2:E}", x, y, z);
//以小寫 e 科學計數法顯示
case "ee":
return String.Format("{0:e} ,{1:e} ,{2:e}", x, y, z);
//對象預設的 ToStrin() 方法顯示
default:
return ToString();
}
}
}
}
運作結果為:
本文就到此結束了,歡迎大家批評指正,一起交流!
Rember ,You Make Luck !