五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

第 52 講:類型良構(gòu)規(guī)范(二):`IFormattable` 接口

2021-07-31 08:29 作者:SunnieShine  | 我要投稿

在說完前文給定的這些基本內(nèi)容后,我們應(yīng)該對面向?qū)ο笥辛艘粋€全新而又陌生的認(rèn)識。這些內(nèi)容對于我們來說不得不去接受,即使它比較多。以后我們會在程序項目里,或者在你自己的程序里使用到它們。為了以后寫出來的代碼更具有可讀性,我們才有了這個篇章的內(nèi)容。

本篇章的內(nèi)容還有非常多其它的東西,除了基本規(guī)范外,我們還要對一些 C# 的庫里自帶的數(shù)據(jù)類型(特別是接口)作出一定程度的介紹,比如

  • IFormattableIFormatProvider

  • IEquatableIComparableIEqualityComparer

  • IDisposable

  • IEnumerableIEnumerator

在這些接口內(nèi)容全部介紹了之后,我們還會給大家介紹 C# 相關(guān)的 SOLID 實現(xiàn)原則,以及設(shè)計模式,這對我們以后寫代碼都會有相當(dāng)大的幫助。

Part 1 自定義格式化處理

考慮使用 Console.WriteLinestring.Format 方法的時候,我們會在最開始的第一個參數(shù)里傳入帶有一定數(shù)量占位符的模式字符串。后面的參數(shù)都是在補充說明占位符的輸出效果,以及填充位、格式等信息。比如說之前說到的:{0:f,10}這樣的字符串,表達的是第 1 個占位符,占 10 個字符空間的顯示長度,并以 "f" 作為格式化字符串來格式化處理數(shù)據(jù)。

如果我們定義了一個自己的數(shù)據(jù)類型的話,我們必然會需要自己對它實現(xiàn)格式化輸出的效果,但它和整數(shù)這些數(shù)據(jù)類型不同,它不是系統(tǒng)自帶的數(shù)據(jù)類型,因此我們不能直接在網(wǎng)上查資料就可以學(xué)會。因此,這里我們要帶給大家的是一個和格式化輸出字符串有關(guān)系的接口:IFormattable 接口。

假設(shè)現(xiàn)在我們設(shè)計了一個數(shù)據(jù)類型叫做“溫度”。這個類型可以以一個數(shù)值的形式表示一個溫度的數(shù)值,并根據(jù)溫度的單位呈現(xiàn)不同的溫度結(jié)果,比如攝氏度、開爾文熱力學(xué)溫度(開氏度)和華氏度。

假設(shè),我們允許用戶輸入一個攝氏度的溫度數(shù)值,然后存儲進去。然后我們可以通過調(diào)用 Fahrenheit 屬性獲取華氏度,或者調(diào)用 Kelvin 屬性獲取開氏度。

思考一點。假設(shè)我想要通過 ToString 獲取字符串結(jié)果,我們目前能夠得到的只能是攝氏度的溫度結(jié)果。但是,我想通過輸出字符串的方式,不同的單位指示,可以有不同的字符串結(jié)果顯示和輸出。最簡單的辦法是使用枚舉類型。

這樣就可以解決問題。那么使用的時候,我們只需要重載一個 ToString 方法,并多傳入一個 TemperatureUnit 類型作為參數(shù)即可:

比如上面這樣的代碼,這種感覺。不過,這樣的代碼不夠靈活,因為我們指定的枚舉類型本身其實指代的是溫度的單位,在這個例子貌似是奏效的;但是換一個例子的話,單獨使用枚舉來表達格式的話,就顯得差點意思。所以,最實在的其實是字符串,這樣也可以省略定義枚舉類型的時間。

那么字符串我們可以這么做。

確實我們也不需要刻意去改變哪里。這樣我們就可以通過這個方法來獲取信息了:

Part 2 更進一步

這樣可以解決很大一部分的問題,不過……按道理來說,既然有了這樣的處理機制后,這個類型應(yīng)該是有辦法自己處理格式化字符串了,不過試試這個代碼:

注意這里我們使用的是 string.Format 方法,傳入的模式字符串是 "{0:F}",其中的 "F" 就是我們在 ToString 重載方法里給出的這個處理了的格式化字符串(即 case "F" 里的這個 "F")。按道理,因為我們自己實現(xiàn)了這個方法,應(yīng)該是有辦法處理格式化字符串了,但……實際上你在程序運行后看到的結(jié)果仍然是 23,而不是華氏度的結(jié)果 73.4(至于怎么得到的 73.4,最開始的那個類型設(shè)計里,Fahrenheit 屬性是給出了公式的,這個就自己去算了)。

問題出在哪里呢?出在它并沒有真正處理格式化字符串,而是從我們自身的角度出發(fā)的、得到的計算公式。因為我們知道調(diào)用這個重載方法就可以得到對應(yīng)結(jié)果了,但機器本身是不知道的。

這可怎么辦呢?別著急,C# 提供了一個手段可以解決這個問題,那就是 IFormattable 接口。如果任何一種數(shù)據(jù)類型能夠?qū)崿F(xiàn)這個接口,那么這個類型就可以這么使用代碼,去得到正確結(jié)果。

不過,你會發(fā)現(xiàn),IFormattable 接口要求你實現(xiàn)一個方法,也叫 ToString,但帶有兩個參數(shù),一個還是 string 類型的格式化字符串(參數(shù)名是 format),而另外一個參數(shù),卻是一個新的接口類型的對象(參數(shù)名是 formarProvider)。這個第二個參數(shù)的類型是 IFormatProvider。看這個名字好像一點用都沒有,我們也沒有接觸過這個接口類型。實際上,規(guī)范化的設(shè)計里,這個類型是用來表示一個專門的類型,這個類型用來專門提供和生成格式化字符串,并提供給別的類型使用的。

舉個例子,假設(shè)我有一個 Temperature 類型表示溫度,因為它的格式化字符串不同可以輸出不同的結(jié)果,于是我們可能會考慮使用重載來搞定。不過,規(guī)范化的設(shè)計里我們是需要再單獨給 Temperature 類型創(chuàng)建一個叫 TemperatureFormatProvider 的類型,這個類型專門用來生成和產(chǎn)生格式化字符串,以便和避免用戶因為不懂格式化字符串而導(dǎo)致無法選擇,進而產(chǎn)生調(diào)用的異常(格式化字符串錯誤之類的)。但是,從這個說法上我們可以看出,實際上 Temperature 類型完全不需要這個所謂的 TemperatureFormatProvider 類型,因為格式化字符串就只有 "F"、"K""C" 三種,就沒有別的了。因此,用戶自己去記住它們就行了,完全沒有必要單獨設(shè)計一個新的類型來幫助用戶得到格式化字符串。

正是因為如此,我們完全可以不必管第二個參數(shù) IFormatProvier formatProvider。但是,我們?yōu)榱耸褂蒙仙厦嫖覀兊哪繕?biāo)功能,我們可以考慮這么去實現(xiàn):

是的,代碼直接從原來那個方法搬過來就行,而第二個參數(shù)我們直接不使用。

順帶一提。參數(shù)的參數(shù)名不需要和基類型或者接口里的這個方法完全一樣。一般來說這個是必須要一樣的,但是其實可以改名字的。

嗯,既然代碼是復(fù)制粘貼過來的,那么原來的單參數(shù)的 ToString 方法我們需要怎么去改變呢?現(xiàn)在我們有三個 ToString 方法了,那么這三個方法的代碼這樣寫比較合適:

我們直接通過使用 ToString(null, default(IFormatProvider))ToString(fprmat, default(IFormatProvider)) 的方式全都去調(diào)用帶兩個參數(shù)的重載 ToString 方法就可以了。至于第二個參數(shù),我們傳什么數(shù)值進去其實都無所謂,因為方法里壓根沒用到。這個時候我們一般寫成 null 或者 default(IFormatProvider)。

null 呢,是所有引用類型的默認(rèn)值,但是萬一我們這個參數(shù)是值類型的,習(xí)慣性地傳入 null 可能會產(chǎn)生編譯器錯誤,告訴你參數(shù)類型不匹配。所以得具體使用的時候要注意。

default(IFormatProvider) 呢,代碼略長,但是更嚴(yán)謹(jǐn)一點。反正這個參數(shù)我們也沒有用到,那干脆為了占一個參數(shù)的位置,總不能啥數(shù)據(jù)都不寫吧。這里我們就寫一個 default 表達式來表達這里參數(shù)我們是傳的默認(rèn)數(shù)值進去。這表示這個參數(shù)的數(shù)據(jù)本身是沒有什么特殊意義的數(shù)據(jù)。

有了這樣的實現(xiàn)后,我們就可以運行程序了。可以看到程序運行結(jié)果確實是從 "23.00 °C" 變成了 "73.40 °F" 了,任務(wù)我們就算完成了。

Part 3 來看下完整的實現(xiàn)

下面我們來看下整個完整的實現(xiàn)吧。


第 52 講:類型良構(gòu)規(guī)范(二):`IFormattable` 接口的評論 (共 條)

分享到微博請遵守國家法律
浮山县| 濮阳县| 南投县| 城口县| 江油市| 台东市| 淮北市| 武义县| 灯塔市| 南岸区| 长乐市| 紫云| 木兰县| 长泰县| 汾西县| 育儿| 那坡县| 嘉荫县| 孟州市| 万宁市| 中宁县| 泰宁县| 玛纳斯县| 共和县| 泗水县| 米泉市| 布尔津县| 荆门市| 武汉市| 崇信县| 普陀区| 肇庆市| 广西| 马公市| 玛多县| 黑山县| 商都县| 景德镇市| 浦江县| 乌兰察布市| 屯昌县|