日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

(转)彻底学通string.Format以及IFormattable,IFormatProvider,ICustomFormatter

發(fā)布時(shí)間:2025/7/14 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (转)彻底学通string.Format以及IFormattable,IFormatProvider,ICustomFormatter 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

此文轉(zhuǎn)自喆 喆的博客,原文鏈接地址:http://www.cnblogs.com/szp1118/archive/2010/07/31/1789148.html

自從使用.net以來(lái)就一直都在使用string.Format方法,一直沒(méi)有空或者其他原因都沒(méi)有深入去了解,主要還是因?yàn)轫?xiàng)目上似乎沒(méi)有這么高的要求,也沒(méi)必要去深入了解,就算碰到了自定義的格式化內(nèi)容也是寫幾個(gè)通用的方法而已。今天空下來(lái)仔細(xì)去理解了一下,在這里和大家分享一下,也希望大家一起交流。

?

string.Format方法是string類提供的靜態(tài)方法,一般最多使用的是其兩個(gè)參數(shù)的重載,例如:

?

var?name?=?"Zhezhe";
var?msg?
=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}?{2}.",?name,?DateTime.Now,?DateTime.Now.DayOfWeek);
Console.WriteLine(msg);

?

后面一個(gè)參數(shù)是.net語(yǔ)法簡(jiǎn)寫的可變參數(shù),在.net內(nèi)部實(shí)際是數(shù)組而已,實(shí)質(zhì)還是兩個(gè)參數(shù)的方法重載。

你也可以不使用這種方法,將字符串相加即可

var?msg1?=?"Hello?Cnblogs,?I?am?"?+?name?+?",Today?is?"?+?DateTime.Now.ToString("yyyy-MM-dd")?+?"?"?+?DateTime.Now.DayOfWeek?+?".";

上面兩種方法的結(jié)果是一樣的。

?之前普遍使用第一種方法的原因是相比string的多個(gè)加號(hào)相加在性能上有一定優(yōu)勢(shì),因?yàn)槠鋬?nèi)部是使用StringBuilder類的,還有一個(gè)原因是代碼的可讀性比起+這樣的方式更好一些。

?

分析一下第一種方法的實(shí)現(xiàn)原理:

?1.Format方法的內(nèi)部解析方式和原理

Format方法在取到第一個(gè)參數(shù)"Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}?{2}."之后便將其分解成多個(gè)部分

①?"Hello?Cnblogs,?I?am?" ??② "{0}" ?③",Today?is ""{1:yyyy-MM-dd}""? ""{2}""."

分解的原則是按照{(diào)}配對(duì)的數(shù)量進(jìn)行的,{}是微軟定義好的標(biāo)記而已,你自己也可以去實(shí)現(xiàn)個(gè)用 []表示都無(wú)所謂。既然{}已經(jīng)被定義為了特殊的標(biāo)記,所以如果是自己需要在字符串中包含大括號(hào)的話就必須進(jìn)行轉(zhuǎn)義,這個(gè)轉(zhuǎn)義也和我們平時(shí)使用的"/"轉(zhuǎn)義表示法不同,需要使用兩個(gè)大括號(hào)進(jìn)行轉(zhuǎn)義如 {{ 或者 }}。 如:

?var?msg2?=?string.Format("Hello?{{}},I?am?{0}",?name);

將{}分解出來(lái)之后根據(jù)中間的序號(hào)來(lái)對(duì)應(yīng)第二個(gè)參數(shù),如果第二個(gè)參數(shù)的實(shí)際個(gè)數(shù)小于需要的數(shù)量,則會(huì)出現(xiàn)運(yùn)行錯(cuò)誤(編譯時(shí)不會(huì)報(bào)錯(cuò)), 如果參數(shù)個(gè)數(shù)大于序號(hào)的數(shù)量,則其后的忽略不計(jì)。

?參數(shù)個(gè)數(shù)小于序號(hào)的實(shí)際數(shù)量,錯(cuò)誤

var?msg4?=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}?{2}.",?name,?DateTime.Now);

參數(shù)個(gè)數(shù)大于序號(hào)的實(shí)際數(shù)量,多出的參數(shù)忽略不計(jì)

?var?msg4?=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}.",?name,?DateTime.Now,DateTime.Now.DayOfWeek);

序號(hào)的順序不一定必須是0,1,2,3,4可以任意排列,但是序號(hào)永遠(yuǎn)和第二個(gè)參數(shù)(實(shí)質(zhì)是數(shù)組)的索引一致。

var?msg4?=?string.Format("Hello?Cnblogs,?I?am?{2},Today?is?{0:yyyy-MM-dd}?{1}.",?DateTime.Now,?DateTime.Now.DayOfWeek,?name);

序號(hào)還能跳躍,但是中間跳躍過(guò)的序號(hào)參數(shù)里必須有

var?msg5?=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{2:yyyy-MM-dd}?{3}.",?name,?"test",?DateTime.Now,?DateTime.Now.DayOfWeek);

?上面講了一下用法,接下來(lái)繼續(xù)

分解完畢之后使用 StringBuilder的Append方法將各個(gè)部分添加進(jìn)去,最后再用ToString方法轉(zhuǎn)成string,其實(shí)現(xiàn)原理非常類似于下面的代碼

var?s?=?new?StringBuilder();
????????????s.Append(
"Hello?Cnblogs,?I?am?");
????????????s.Append(name);
????????????s.Append(
",Today?is?");
????????????s.Append(DateTime.Now.ToString(
"yyyy-MM-dd"));
????????????s.Append(
"?");
????????????s.Append(DateTime.Now.DayOfWeek);
????????????s.Append(
".");
????????????var?msg3?
=?s.ToString();

順便解釋一下string和StringBuilder:string雖然也是引用類型,但是該類型.net內(nèi)部進(jìn)行了特殊處理,讓其表現(xiàn)出和值類型相似的特征,特別是在每次變動(dòng)之后就會(huì)重新分配內(nèi)存空間,而StringBuilder就不會(huì),所以如果有很多個(gè)字符串相加拼接,則string性能較低。

在用 Append方法進(jìn)行添加的時(shí)候會(huì)有兩種情況:

一種是{0},{1}這樣的不帶有特殊格式化的則直接會(huì)調(diào)用該對(duì)象的ToString方法,比如上面的 ?s.Append(DateTime.Now.DayOfWeek);其實(shí)就是 s.Append(DateTime.Now.DayOfWeek.ToString());在.net中,如果是自己定義的類,并且沒(méi)有重寫ToString方法,則會(huì)輸出類的全名,下面會(huì)詳細(xì)討論。

另一種是{0:yyyy-MM-dd}帶有特殊格式化的則繼續(xù)分解,將冒號(hào)后面的內(nèi)容分解出來(lái),并且在調(diào)用ToString時(shí)作為參數(shù)傳入,上面的s.Append(DateTime.Now.ToString("yyyy-MM-dd"));就體現(xiàn)了這一點(diǎn)。所以這些其實(shí)都沒(méi)什么奧妙可言,冒號(hào)也是一個(gè)預(yù)定義好的標(biāo)記而已,如果微軟讓你去實(shí)現(xiàn)這個(gè),你也可以用其他符號(hào)。

?

2.ToString方法的深入理解

通過(guò)第一步的分析如果純粹從分析Format這個(gè)方法來(lái)說(shuō)已經(jīng)足夠了,大括號(hào)的特殊標(biāo)記作用以及和后面參數(shù)的對(duì)應(yīng)關(guān)系也已經(jīng)解釋清楚了。但是這里還是需要深入了解一下ToString方法。

上面1中提到如果一個(gè)自己定義的類不去重寫ToString方法的話則會(huì) 輸出類的全名,例如

public?class?Person
????{
????????
public?string?Name?{?get;?set;?}
????}

如果寫如下代碼

var?msg6?=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}?{2}.",
?????????????????????????????????????
new?Person()?{Name?=?"Zhezhe"},?DateTime.Now,?DateTime.Now.DayOfWeek);
????????????Console.WriteLine(msg6);

則會(huì)輸出:

?這里再次強(qiáng)調(diào)一下,如果某個(gè)對(duì)象需要轉(zhuǎn)換成ToString,并且沒(méi)有手動(dòng)調(diào)用該方法,程序會(huì)自動(dòng)調(diào)用該方法,上面的new?Person()?{Name?=?"Zhezhe"}沒(méi)有手工調(diào)用,程序會(huì)自動(dòng)調(diào)用方法(new?Person()?{Name?=?"Zhezhe"}).ToString(); 這個(gè)是微軟讓你少些代碼而已,好的習(xí)慣是始終寫上 .ToString();

.net中的任何對(duì)象都具有該方法,因?yàn)樵摲椒ㄔ趏bject對(duì)象中定義,任何類或者結(jié)構(gòu)都會(huì)繼承object,所以不用擔(dān)心一個(gè)對(duì)象沒(méi)有ToString方法。

接下來(lái)定義帶有ToString重載方法的類

public?class?PersonWithToString
????{
????????
public?string?Name?{?get;?set;?}

????????
public?override?string?ToString()
????????{
????????????
return?Name;
????????}
????}

編寫如下代碼:

?//使用自己定義類,但是重寫了ToString方法
var?msg7?=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}?{2}.",?new?PersonWithToString(){?Name?=?"Zhezhe"?},?DateTime.Now,?DateTime.Now.DayOfWeek);
Console.WriteLine(msg7);

輸入結(jié)果為 輸出就正常了,自己重寫的方法起作用了。

總結(jié):對(duì)自己定義的類始終重寫 ToString方法。 這樣在 string.Format 中或者其他需要程序自動(dòng)轉(zhuǎn)換成string類型時(shí)不會(huì)出現(xiàn) 輸出類全名的情況。

?

3.ToString帶有自定義格式化參數(shù)的理解

上面講到的ToString都是不帶格式化參數(shù)的,像 ?{1:yyyy-MM-dd} 這樣的情況是沒(méi)法處理的,也許有人會(huì)說(shuō)像 DateTime.Now.ToString("yyyy-MM-dd") 這樣的情況自己去重載一個(gè)ToString方法就可以了,果真如此嗎? 下面就測(cè)試一下

public?class?PersonWithToString
????{
????????
public?string?Name?{?get;?set;?}

????????
public?override?string?ToString()
????????{
????????????
return?Name;
????????}

????????
public?string?ToString(string?format)
????????{
????????????
switch?(format)
????????????{
????????????????
case?"UPP":
????????????????????
return?Name.ToUpper();
????????????????
case?"LOW":
????????????????????
return?Name.ToLower();
????????????????
default:
????????????????????
return?Name;
????????????}
????????}
????}

?

var?msg9?=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}?{2}.",
??????????????????????????????????
new?PersonWithToString()?{?Name?=?"Zhezhe"?}.ToString("UPP"),?DateTime.Now,?DateTime.Now.DayOfWeek);
????????????Console.WriteLine(msg9);

msg9的實(shí)際輸出為 Hello Cnblogs, I am ZHEZHE,Today is 2010-07-30 Friday.? 這個(gè)正是我們需要的,當(dāng)然,這個(gè)肯定是對(duì)的,要不然就是.net的bug了

接下來(lái)再看看下面的

var?msg8?=?string.Format("Hello?Cnblogs,?I?am?{0:UPP},Today?is?{1:yyyy-MM-dd}?{2}.",
??????????????????????????????????
new?PersonWithToString()?{?Name?=?"Zhezhe"?},?DateTime.Now,?DateTime.Now.DayOfWeek);

實(shí)際輸出是: Hello Cnblogs, I am Zhezhe,Today is 2010-07-30 Friday.? 并不是我們所期望的。實(shí)際上上面的代碼是調(diào)用了PersonWithToString類的不帶參數(shù)的ToString()方法。言外之意就是? ?{0:UPP}這樣的格式實(shí)際上內(nèi)部處理的是和 ?{0}

一樣的效果了。在1中提到了分解的原理用了類似兩個(gè)字,實(shí)際情況并不是這么簡(jiǎn)單。

?? {0:UPP} 真正調(diào)用的方法簽名是??? string ToString(string format,IFormatProvider formatProvider)

而且也不是直接調(diào)用該對(duì)象的此方法。而是通過(guò)?IFormattable 接口實(shí)現(xiàn)的方法

?現(xiàn)在定義實(shí)現(xiàn)了該接口的 Person2類

?

Person2 public?class?Person2?:?IFormattable
????{
????????
public?string?Name?{?get;?set;?}

????????
public?override?string?ToString()
????????{
????????????
return?Name;
????????}

????????
#region?IFormattable?Members

????????
public?string?ToString(string?format,?IFormatProvider?formatProvider)
????????{
????????????
if?(string.IsNullOrEmpty(format))
????????????????
return?ToString();

????????????
switch?(format)
????????????{
????????????????
case?"UPP":
????????????????????
return?Name.ToUpper();
????????????????
case?"LOW":
????????????????????
return?Name.ToLower();
????????????????
default:
????????????????????
return?Name;
????????????}
????????}

????????
#endregion
????}

?運(yùn)行一下代碼得到預(yù)期的結(jié)果

??//使用實(shí)現(xiàn)了IFormattable接口的Person2對(duì)象
var?msg10?=?string.Format("Hello?Cnblogs,?I?am?{0:UPP},Today?is?{1:yyyy-MM-dd}?{2}.",
new?Person2()?{?Name?=?"ZhezheToUpper"?},?DateTime.Now,?DateTime.Now.DayOfWeek);
Console.WriteLine(msg10);

?ZhezheToUpper已經(jīng)輸出成全部大寫形式了。

?

既然{0:UPP}會(huì)調(diào)用接口定義的ToString方法,那么{0}呢? 如果該類沒(méi)有實(shí)現(xiàn)IFormattable接口,上面已經(jīng)說(shuō)了,會(huì)調(diào)用重載的或者是基類的ToString()方法。但是如果該類已經(jīng)實(shí)現(xiàn)了IFormattable接口,那么{0}也不會(huì)去調(diào)用重載的或者是基類的ToString()方法了,它始終是去調(diào)用 接口定義的 ToString方法。下面具體印證一下

?

Person3 ?public?class?Person3?:?IFormattable
????{
????????
public?string?Name?{?get;?set;?}

????????
public?override?string?ToString()
????????{
????????????
return?Name;
????????}

????????
#region?IFormattable?Members

????????
public?string?ToString(string?format,?IFormatProvider?formatProvider)
????????{
????????????
if?(string.IsNullOrEmpty(format))
????????????????
return?Name?+?"?IFormattable?Method";

????????????
switch?(format)
????????????{
????????????????
case?"UPP":
????????????????????
return?Name.ToUpper();
????????????????
case?"LOW":
????????????????????
return?Name.ToLower();
????????????????
default:
????????????????????
return?Name?+?"?IFormattable?Method";
????????????}
????????}

????????
#endregion
????}

?

運(yùn)行下面的測(cè)試代碼

var?msg11?=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}?{2}.",
??????????????????????????????????
new?Person3()?{?Name?=?"ZhezheToUpper"?},?DateTime.Now,?DateTime.Now.DayOfWeek);
????????????Console.WriteLine(msg11);?

?

輸出為: Hello Cnblogs, I am ZhezheToUpper IFormattable Method,Today is 2010-07-30 Friday.

證明了確實(shí)是調(diào)用了接口定義的方法,而不是重載的ToString方法,否則是輸出ZhezheToUpper

再來(lái)看一下Person2中實(shí)現(xiàn)的ToString方法,

?if (string.IsNullOrEmpty(format))
??????????????? return ToString();
如果是剛才的{0}不帶格式化參數(shù)的調(diào)用,則format參數(shù)傳過(guò)來(lái)的是null值,這里需要自己判斷,如果是null值,一般情況下是手工去調(diào)用重載的ToString()方法。
所以Person2的做法是好的,而Person3中的做法是不好的,Person3只是為了測(cè)試分辨出調(diào)用的是哪個(gè)方法才這么設(shè)計(jì)的。

?

總結(jié):一.對(duì)于實(shí)現(xiàn)IFormattable 接口時(shí),如果format參數(shù)為null(即不帶格式化參數(shù)的情況,如{0})則應(yīng)該調(diào)用重載的 ToString()方法,而不應(yīng)該自己去另外寫代碼。

二.如果找不到相應(yīng)的格式化參數(shù),例如{0:AAA},在Person2的switch中并無(wú)匹配的AAA,這種情況一般也應(yīng)該去調(diào)用重載的 ToString()方法。

否則就會(huì)出現(xiàn)

?

?//以下兩個(gè)輸出結(jié)果不一樣,是不合理的
var?msg12?=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}?{2}.",new?Person3()?{?Name?=?"ZhezheToUpper"?},?DateTime.Now,?DateTime.Now.DayOfWeek);
Console.WriteLine(msg12);

var?msg13?
=?string.Format("Hello?Cnblogs,?I?am?{0},Today?is?{1:yyyy-MM-dd}?{2}.",new?Person3()?{?Name?=?"ZhezheToUpper"?}.ToString(),?DateTime.Now,?DateTime.Now.DayOfWeek);
Console.WriteLine(msg13);

?

不同的結(jié)果的情況

上面的輸出結(jié)果不同:

?這是不好的設(shè)計(jì)

?

?4.繼續(xù)了解 IFormatProvider?和 ICustomFormatter 接口

到這里為止,應(yīng)該說(shuō)靈活應(yīng)用string.Format()已經(jīng)沒(méi)什么多大的問(wèn)題了,但是也還是存在一些問(wèn)題,比如我們必須得為每個(gè)類單獨(dú)去實(shí)現(xiàn)IFormattable接口才能實(shí)現(xiàn)自定義的格式化參數(shù)。在一些場(chǎng)后還是覺(jué)得不太方便或者說(shuō)代碼冗余。

.net的string.Format靜態(tài)方法還提供了重載方法,具體簽名如下:public static string Format(IFormatProvider provider,string format,params Object[] args)

?

這個(gè)方法比起原來(lái)使用的方法最前面增加了 IFormatProvider類型參數(shù)。使用此方法的優(yōu)點(diǎn)是不需要為后面的參數(shù)對(duì)象實(shí)現(xiàn) IFormattable? 接口就可以使用自定義的格式化參數(shù)。既然這樣的話也就解決了第4部分開(kāi)頭提到的問(wèn)題了。

?

還是用例子說(shuō)話吧

下面是正方形類

Square類 public?class?Square
????{
????????
public?string?Name?{?get;?set;?}

????????
///?<summary>
????????
///?邊長(zhǎng)
????????
///?</summary>
????????public?double?Side?{?get;?set;?}

????????
public?override?string?ToString()
????????{
????????????
return?string.Format("{0}(Side:{1})",Name,?Side);
????????}
????}

?

下面是長(zhǎng)方形類

?

Rectangle類 ?public?class?Rectangle
????{
????????
public?string?Name?{?get;?set;?}

????????
///?<summary>
????????
///?寬
????????
///?</summary>
????????public?double?Width?{?get;?set;?}

????????
///?<summary>
????????
///?高
????????
///?</summary>
????????public?double?Height?{?get;?set;?}


????????
public?override?string?ToString()
????????{
????????????
return?string.Format("{0}(Width:{1},Height:{2})",Name,?Width,?Height);
????????}
????}

?

?兩個(gè)類都重寫了ToString方法

定義MyHelloFormatProvider類,該類從名稱上就可以看出是格式化的提供者

?

?public?class?MyHelloFormatProvider?:?IFormatProvider
????{
????????
#region?IFormatProvider?Members

????????
public?object?GetFormat(Type?formatType)
????????{
????????????
return?new?MyHelloFormatter();
????????}

????????
#endregion
????}

?

該類實(shí)現(xiàn)了 IFormatProvider 接口,接口只有一個(gè)唯一的方法需要實(shí)現(xiàn),GetFormat返回的是真正進(jìn)行格式化操作的類,這里很像是工廠模式。

返回 MyHelloFormatter 對(duì)象之后,在MyHelloFormatter 中具體進(jìn)行格式化操作。

?public?class?MyHelloFormatter?:?ICustomFormatter
????{
????????
#region?ICustomFormatter?Members

????????
public?string?Format(string?format,?object?arg,?IFormatProvider?formatProvider)
????????{
????????????var?t?
=?"Hello?";
????????????
switch?(format)
????????????{
????????????????
case?"UPP":
????????????????????t?
=?t.ToUpper();
????????????????????
break;
????????????????
case?"LOW":
????????????????????t?
=?t.ToLower();
????????????????????
break;
????????????????
default:
???????????????????
break;
????????????}

????????????
return?t?+?arg.ToString();
????????}

????????
#endregion
????}

?

?

MyHelloFormatter?實(shí)現(xiàn)了ICustomFormatter接口,該接口也只有一個(gè)唯一的方法,即實(shí)際執(zhí)行格式化的方法

如果不使用格式化參數(shù)或者格式化參數(shù)不匹配,情況會(huì)怎么樣?

?

代碼 var?msg15?=?string.Format(new?MyHelloFormatProvider(),?"{0}??{1}",?new?Rectangle()?{?Name?=?"MyRectangle",?Width?=?14.3,?Height?=?10?},?new?Square()?{?Name?=?"MySquare",?Side?=?24.2?});
????????????Console.WriteLine(msg15);

????????????var?msg16?
=?string.Format(new?MyHelloFormatProvider(),?"{0}??{1}",?new?Rectangle()?{?Name?=?"MyRectangle",?Width?=?14.3,?Height?=?10?}.ToString(),?new?Square()?{?Name?=?"MySquare",?Side?=?24.2?}.ToString());
????????????Console.WriteLine(msg16);

????????????var?msg17?
=?string.Format(new?MyHelloFormatProvider(),?"{0:AAA}??{1:BBB}",?new?Rectangle()?{?Name?=?"MyRectangle",?Width?=?14.3,?Height?=?10?},?new?Square()?{?Name?=?"MySquare",?Side?=?24.2?});
????????????Console.WriteLine(msg17);

?

以上輸出都是一樣的: Hello MyRectangle(Width:14.3,Height:10)? Hello MySquare(Side:24.2)?

上面的運(yùn)行結(jié)果表明,如果提供了new?MyHelloFormatProvider() ,那么執(zhí)行過(guò)程過(guò)是: 根據(jù)MyHelloFormatProvider 對(duì)象得到 MyHelloFormatter?對(duì)象,利用MyHelloFormatter?對(duì)象的Format方法進(jìn)行格式化

這里還有一個(gè)問(wèn)題,如果 MyHelloFormatProvider?的 GetFormat返回的不是一個(gè)實(shí)現(xiàn)了 ICustomFormatter 接口的對(duì)象又會(huì)是什么情況呢?

答案是會(huì)報(bào)異常。 那么如果返回的是 null 呢? 答案是直接調(diào)用了對(duì)象的ToString()方法了。如果返回null,則運(yùn)行結(jié)果如下:

MyRectangle(Width:14.3,Height:10)? MySquare(Side:24.2)?

?

帶上格式化參數(shù)的運(yùn)行結(jié)果

?

var?msg18?=?string.Format(new?MyHelloFormatProvider(),?"{0:UPP}??{1:LOW}",?new?Rectangle()?{?Name?=?"MyRectangle",?Width?=?14.3,?Height?=?10?},?new?Square()?{?Name?=?"MySquare",?Side?=?24.2?});
????????????Console.WriteLine(msg18);

?

?HELLO MyRectangle(Width:14.3,Height:10)? hello MySquare(Side:24.2)


?通過(guò)上面的例子我們知道如果我們需要定義一種通用的格式化方式的話,不需要讓類實(shí)現(xiàn) IFormattable 接口,可以通過(guò)定義實(shí)現(xiàn) IFormatProvider,ICustomFormatter接口的類去做,上面的無(wú)論是正方形還是長(zhǎng)方形類都需要在前面加上 Hello 進(jìn)行格式化,可以是普通的,小寫的,大寫的等等,不需要兩個(gè)類單獨(dú)去實(shí)現(xiàn)了,就選以后增加了圓形,三角形等等,也都能用我們已經(jīng)定義好的 MyHelloFormatProvider 和 MyHelloFormatter? 去進(jìn)行格式化。

?

?

使用這種方式還能解決另外一個(gè)問(wèn)題,假如我們已經(jīng)為圓形類實(shí)現(xiàn)了 IFormattable? 接口,并且已經(jīng)實(shí)現(xiàn)了{(lán)0:UPP}格式化參數(shù),但是實(shí)現(xiàn)的方法中沒(méi)有加{0:LOW}格式化參數(shù),而且這個(gè)類我們又不能更改(可能是.net自帶的類,可能是第三方dll提供的類等等),那該怎么辦呢? 顯然已經(jīng)不可能靠IFormattable? 接口來(lái)解決了

使用這節(jié)講的方法就可以實(shí)現(xiàn)我們要求了。以下是具體實(shí)現(xiàn)

圓形類 public?class?Circle?:?IFormattable
????{
????????
public?string?Name?{?get;?set;?}

????????
///?<summary>
????????
///?半徑
????????
///?</summary>
????????public?double?Radius?{?get;?set;?}

????????
public?override?string?ToString()
????????{
????????????
return?string.Format("{0}(Radius:{1})",?Name,?Radius);
????????}

????????
#region?IFormattable?Members

????????
public?string?ToString(string?format,?IFormatProvider?formatProvider)
????????{
????????????
if?(string.IsNullOrEmpty(format))
????????????????
return?ToString();

????????????var?t?
=?"Hello?";
????????????
switch?(format)
????????????{
????????????????
case?"UPP":
????????????????????t?
=?t.ToUpper();
????????????????????
break;
????????????????
default:
????????????????????
break;
????????????}

????????????
return?t?+?Name;
????????}

????????
#endregion
????}

?

該類可以實(shí)現(xiàn)UPP格式化參數(shù)的格式化。

?var?msg19?=?string.Format("Test:?{0}",?new?Circle()?{?Name?=?"MyCircle",?Radius?=?10?});
????????????Console.WriteLine(msg19);

????????????var?msg20?
=?string.Format("Test:?{0:UPP}",?new?Circle()?{Name?=?"MyCircle",?Radius?=?10});
????????????Console.WriteLine(msg20);

?

運(yùn)行上面的代碼得到:

Test: MyCircle(Radius:10)
Test: HELLO MyCircle

第一個(gè)無(wú)格式化參數(shù),實(shí)際調(diào)用ToString()方法得到,由代碼?if?(string.IsNullOrEmpty(format))決定

第二個(gè)帶UPP格式化參數(shù),也得到了預(yù)期的結(jié)果。

?

現(xiàn)在需要實(shí)現(xiàn)LOW的格式化參數(shù)

var?msg21?=?string.Format(new?MyHelloFormatProvider(),"Test:?{0:LOW}",?new?Circle()?{?Name?=?"MyCircle",?Radius?=?10?});
????????????Console.WriteLine(msg21);?

?

在不修改Circle類并且不重新定義其他類的情況下就可以達(dá)到我們的要求了

顯示結(jié)果如下: Test: hello MyCircle(Radius:10)      hello已經(jīng)是全部小寫了。

轉(zhuǎn)載于:https://www.cnblogs.com/JhoneLee/archive/2013/05/08/3066950.html

總結(jié)

以上是生活随笔為你收集整理的(转)彻底学通string.Format以及IFormattable,IFormatProvider,ICustomFormatter的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。