最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

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

第 55 講:類型良構(gòu)規(guī)范(五):`IEnumerable` 接口

2021-08-12 07:04 作者:SunnieShine  | 我要投稿

今天我們要完成最后一個常用接口的學(xué)習(xí):IEnumerable 接口。IEnumerable 接口是最常見也是最重要的接口類型,它的重要程度基本上遠(yuǎn)超過 IDisposable 接口,基本和 IEquatableIComparable 接口可以并駕齊驅(qū)。但是呢,內(nèi)容可能也不是你想象得那么簡單,所以需要多思考今天的東西。

Part 1 IEnumerable 接口和 foreach 循環(huán)

試想一下,像是 ArrayList 這樣的數(shù)據(jù)結(jié)構(gòu),可以從類型本身就可以看出,它并不是基本的數(shù)據(jù)類型。但為什么這樣的數(shù)據(jù)類型也直接支持 foreach 循環(huán)呢?難道它有什么魔法嗎?

這是因?yàn)椋?/span>只要這個類型實(shí)現(xiàn)了 IEnumerable 接口后,這個類型就可以使用 foreach 循環(huán)了。它和前一節(jié)說明 IDisposable 接口和 using 聲明的規(guī)則差不多:只要實(shí)現(xiàn)了 IDisposable 接口,這個對象類型就可以使用 using 指令來完成對象內(nèi)存自動釋放的行為。那么,我們?nèi)绾稳プ约簩?shí)現(xiàn) IEnumerable 接口呢?下面我們將給大家介紹兩種可實(shí)現(xiàn) IEnumerable 接口的方式。

Part 2 通過可自動迭代的類型直接實(shí)現(xiàn)

2-1 引例

考慮一種情況,我現(xiàn)在實(shí)現(xiàn)了一個數(shù)據(jù)類型,叫 List。這個數(shù)據(jù)類型和 ArrayList 差不多,不過是我自己實(shí)現(xiàn)的數(shù)據(jù)類型。大概設(shè)計(jì)的代碼有這樣一些:

因?yàn)檫@個對象類型沒有實(shí)現(xiàn) IEnumerable 接口,因此我們并不能使用如下的代碼書寫格式:

現(xiàn)在,我們就把這個不可能變?yōu)榭赡堋?/span>

首先,我們思考一下,我們要想讓整個序列產(chǎn)生迭代,顯然我們不能直接使用這個 _elements 字段完成,因?yàn)檫@個字段里一共可以容納 10 個元素(請注意參看 MaxCapacity 常量在這個類型里的使用),但是我們并不一定讓這個類型裝滿 10 個元素,所以這個數(shù)組是有空位的。那么,我們需要把數(shù)組的其中前面的那一部分取出來,然后作為結(jié)果迭代出來。因此,我們需要專門寫一個方法,來把有效的數(shù)據(jù)取出來。

有效的數(shù)據(jù)只有哪些呢?在這個類型里包含一個 _count 字段記錄了目前存儲了多少個元素,這正好可以完成我們的任務(wù):我們只需要提取從第 0 號下標(biāo)的元素到第 _count - 1 號下標(biāo)的元素就可以了。因?yàn)閿?shù)組是從 0 開始算下標(biāo)的,所以 0 到 _count - 1 一共是 _count 個元素。

那么,我們可以這么去設(shè)計(jì)代碼:

即直接拷貝 _elements 數(shù)組里的元素到 result 里,然后返回出去即可。當(dāng)然,因?yàn)閿?shù)組從 Array 類型派生,因此 Array 類型里包含一個 Copy 靜態(tài)方法,可以直接完成我們的拷貝復(fù)制數(shù)組元素的任務(wù),而不需要自己寫循環(huán):

簡單說一下 Array.Copy(_elements, 0, result, 0, _count); 語句的五個參數(shù)的意思。

  • 第一個參數(shù)(_elements):表示拷貝數(shù)組的時候,從哪個數(shù)組里取數(shù)據(jù);

  • 第二個參數(shù)(0):表示拷貝數(shù)組的時候,從這個數(shù)組的哪個下標(biāo)開始;

  • 第三個參數(shù)(result):表示拷貝數(shù)組的時候,拷貝到哪個數(shù)組里去;

  • 第四個參數(shù)(0):表示拷貝數(shù)組的時候,這個接收的數(shù)組從哪個下標(biāo)開始往后放元素;

  • 第五個參數(shù)(_count):表示拷貝多少個元素。

這個方法相當(dāng)好用,它避免了你手寫循環(huán)帶來的隱藏的 bug。這個方法甚至可以移動數(shù)組里的元素,即第一個和第三個參數(shù)傳入同樣的數(shù)組,這個方法也是可以完成任務(wù)的,只要你寫的數(shù)據(jù)是合適的。

但是切記,result 數(shù)組要能使用 Array.Copy 方法之前,需要先自己 new 一下,因?yàn)?result 如果沒有合理初始化的話,參數(shù)是不能參與使用的,甚至?xí)a(chǎn)生異常。一定要保證這個數(shù)組用 new 初始化的時候,初始化容量要足夠放一會兒存進(jìn)來的所有元素。

有了這個之后,ToArray 方法最終會返回一個新的數(shù)組,表示里面的合理的數(shù)據(jù)。因此,我們?yōu)榱俗屵@個 List 類型可以使用 foreach 循環(huán),我們需要做如下兩個步驟。

2-2 在類型聲明上添加 IEnumerable 接口

這么寫就可以了:

需要注意的是,今天說的 IEnumerable 接口并不在 System 命名空間里,而是在 System.Collections 里。這個是第一個目前沒有在 System 命名空間里的類型。因此,如果要寫上接口名,你需要添加 using 指令:

或者是直接寫全名:

都是可以的。這樣就算完成了第一步。

不過,接口里面的方法還沒實(shí)現(xiàn)呢。沒關(guān)系,馬上我們來說怎么去實(shí)現(xiàn)。

2-3 實(shí)現(xiàn) IEnumerable 接口

這個接口有點(diǎn)繞的地方是,它里面需要實(shí)現(xiàn)的方法是這樣的:

這個接口稍微有點(diǎn)麻煩的地方是,這個里面唯一一個需要實(shí)現(xiàn)的成員是一個方法,并且返回了一個新的接口類型:IEnumerator 接口。這個接口是什么東西呢?

如果 IEnumerable 接口是用來和 foreach 綁定起來的迭代器,那么 IEnumerator 就是提供迭代功能的提供方。這么說不太懂,你可以把 IEnumerable 接口想象成一個完整的工具,它包裹了一系列的功能可以提供給你直接用;但是 IEnumerator 接口則是這個完整工具的其中一個部件,它的存在才保證了這個工具的這個功能能夠得以使用。

而實(shí)際上,數(shù)組本身已經(jīng)實(shí)現(xiàn)了這一套的迭代功能,所以,你可以這么去寫代碼:

此時的 ToArray 方法就是前面我們實(shí)現(xiàn)的方法;而這個方法的結(jié)果是一個 int[]。我們經(jīng)常使用 foreach 循環(huán),就是因?yàn)檫@個數(shù)組本身就已經(jīng)實(shí)現(xiàn)了 IEnumerable 接口,所以我們可以直接使用 GetEnumerator 方法。

另外,這個語句放在哪里呢?放在 List 類型里的需要實(shí)現(xiàn)的 GetEnumerator 方法里:

這樣就 OK 了。因?yàn)槟銓?shí)現(xiàn)了 List 類型的 IEnumerable 接口了,因此,我們直接可以直接使用 foreach 循環(huán)對于 List 類型的對象了:

注意,第 7 行代碼寫的是 object element in l 而不是 int element in l,這一點(diǎn)我們將在后面的內(nèi)容給大家介紹原因。實(shí)際上這里是可以寫 int element in l 的,不過它牽扯到轉(zhuǎn)換機(jī)制需要后面一節(jié)才能講明白。這里就先不說了。

最后順帶一說,所有的循環(huán)過程都稱為迭代(Iteration)。比如說 foreach 循環(huán),我們需要寫成 foreach (object element in list) 的格式,那么這里就可以說成“我現(xiàn)在在用 foreach 迭代 list 列表”。就是這么一個說法。

Part 3 自己實(shí)現(xiàn)迭代器

3-1 foreach 循環(huán)的等價代碼以及原理

要知道,foreach 循環(huán)等價于如下的這個行為:

簡單說一下這個代碼的意思。首先第一行 enumeratorinstance.GetEnumerator 初始化。這個 instance 假設(shè)為某個已經(jīng)實(shí)現(xiàn)了 IEnumerable 接口的類型實(shí)例化出來的對象實(shí)例;然后 GetEnumerator 方法的調(diào)用,就是我們前面實(shí)現(xiàn)的 IEnumerable 接口里這個必須實(shí)現(xiàn)的方法 GetEnumerator

接著,foreach 改成了一個 while 循環(huán)。循環(huán)的條件是看這個 enumerator 是否能“前進(jìn)”。此時,你把 enumerator 變量想象成指向數(shù)組的第一個元素的“頭指針”,每執(zhí)行一次 MoveNext 方法的時候,這個“指針”就會往后移動一個元素單位,指向第二個元素;接著是第三個元素、第四個元素,等等。如果“指針”可以往下移動,那么 MoveNext 方法就會返回 true;如果元素到底了,foreach 相當(dāng)于說是要終結(jié)了,那么這個 MoveNext 方法的調(diào)用就會得到 false 的結(jié)果,這樣 while 循環(huán)就不再得到執(zhí)行。

接著,在 while 循環(huán)里面,我們使用 enumerator.Current 來獲取當(dāng)前“指針”指向的元素到底是哪個。然后你可以在里面寫一些很復(fù)雜的處理代碼,什么 if 啊之類的,都是可以的,只要你知道了 enumerator.Current 用于取值就 OK。

最后,在 while 條件不成立,即整個循環(huán)都執(zhí)行完成后,整個 while 循環(huán)結(jié)束,這也就意味著我們等價的 foreach 循環(huán)也就結(jié)束了。這個是 foreach 的底層。

3-2 完成迭代器實(shí)現(xiàn)

如果你需要對性能要求較高的話,在值類型(結(jié)構(gòu))實(shí)現(xiàn) IEnumerable 很有可能導(dǎo)致裝箱,或者復(fù)雜的處理實(shí)例化一個引用類型的對象處理,導(dǎo)致性能的損失。C# 為我們提供了一種機(jī)制,使得我們甚至不需要實(shí)現(xiàn) IEnumerable 接口也可以使用 foreach 循環(huán),不過這個處理就比較麻煩了。

3-2-1 鴨子類型的概念

要想知道我們?nèi)绾问褂孟旅娴膬?nèi)容,我們必須引入一個新的概念:鴨子類型(Duck Type)。鴨子類型是一個術(shù)語(盡管這個詞你不一定看得出來它是一個術(shù)語詞),它表示一種數(shù)據(jù)類型,即使不實(shí)現(xiàn)接口,C# 語言也可以讓其支持一些特殊語法的魔法。

鴨子類型的“鴨子”取自一句編程界英語里的諺語:如果這個玩意兒長得像鴨子,叫聲像鴨子,那么它就是鴨子。這句話看起來好像有著很多邏輯問題,但它被廣泛使用到編程里。

如果一個數(shù)據(jù)類型,滿足 C# 語法里規(guī)定的一些指定條件的話,那么它即使不去實(shí)現(xiàn)接口,也相當(dāng)于是做到了接口該做的事情,那么這個類型我們就稱為鴨子類型。就比如說前文說到的這個 IEnumerable 接口。

3-2-2 可使用 foreach 循環(huán)的鴨子類型條件

如果一個類型滿足了如下的條件,那么這個類型就是可以使用 foreach 循環(huán)的:這個數(shù)據(jù)類型包含一個 public 修飾的 GetEnumerator 方法,并返回一個數(shù)據(jù)類型(本來是返回 IEnumerator 類型的對吧)需要滿足如下的條件:

  1. 這個數(shù)據(jù)類型里帶有 public 修飾的、非靜態(tài) Current 屬性;

  2. 這個數(shù)據(jù)類型里帶有 public 修飾的、非靜態(tài) MoveNext 方法,無參但返回 bool 類型。

只要滿足這樣的條件,那么這個類型就可以作為 IEnumerator 的替代者,然后整個類型也不需要實(shí)現(xiàn) IEnumerable 接口,也可以使用 foreach 循環(huán)。

3-2-3 例子

假設(shè)我有一個 BitSet 的結(jié)構(gòu),它用來存儲和記錄哪些編號上的位置是“開”還是“關(guān)”的值。舉個例子吧,比如我要表示這個班級哪些人及格了,我用 BitSet 類型(把學(xué)生先編號 1 到 64),然后把對應(yīng)編號上的數(shù)位用 1 表示這個人及格了,而 0 表示這個人沒及格。大概 BitSet 類型這么用,那么它的基本實(shí)現(xiàn)是這樣的:

比如說我這么使用代碼:

就可以把一系列的元素追加到 BitSet 的實(shí)例里去。那么,這個類型要想遍歷里面所有是 1 的數(shù)值的編號,怎么做呢?

3-3 實(shí)現(xiàn) Enumerator 嵌套結(jié)構(gòu)

我們必須從低自上分析和構(gòu)建這個數(shù)據(jù)類型。因?yàn)槲覀冃枰褂?GetEumerator 方法來完成 BitSet 數(shù)據(jù)類型的 foreach 循環(huán)的使用功能,但因?yàn)樗枰祷匾粋€非 IEnumerator 的數(shù)據(jù)類型,但我們尚未實(shí)現(xiàn),所以我們需要先實(shí)現(xiàn)這個替代數(shù)據(jù)類型。

這里最合適的做法是,在 BitSet 的下面追加一個嵌套結(jié)構(gòu)叫做 Enumerator,專門表示一個用于實(shí)現(xiàn) Current 屬性和 MoveNext 方法的類型。然后,因?yàn)樗鼘?shí)現(xiàn)了這些成員,因此我們可以套用到 BitSet 類型里面需要實(shí)現(xiàn)的 GetEnumerator 方法里當(dāng)返回值了:

不過這里稍微要注意的是,這個 Enumerator 是為這個 BitSet 類型服務(wù)的,但因?yàn)?BitSet 是實(shí)例在迭代,因此如果不給 Enumerator 傳遞這個實(shí)例的話,那么 Enumerator 到底應(yīng)該迭代什么東西呢?所以,我們需要完成 this 實(shí)例的傳入,才能保證下面能夠使用上這些合適的數(shù)據(jù)。

那么,我們來實(shí)現(xiàn) Enumerator 類型吧。

如代碼所示,這樣的代碼就算是完成了對 Enumerator 類型的一個基本實(shí)現(xiàn)過程。首先,我們需要把 BitSet 里的這個掩碼 _mask 字段傳過來,因?yàn)樗怯脕淼?;接著,我們要給 _index 字段賦值 -1。這個 _index 字段就表示我們一會兒要迭代返回出去的編號。初始化的時候賦值的是 -1 而不是 0,一會兒我們來說為什么。

接著,我們因?yàn)橐?_index 字段作為迭代的結(jié)果返回出去,所以我們的 Current 屬性的 get 方法里寫的是 return _index;。最后我們來看 MoveNext 方法,也是這個類型里最難的方法。

這個方法主要是控制每次 while 循環(huán)的條件。既然是條件,那么必然是用返回值體現(xiàn)“我這次移動游標(biāo)是不是可以”。我們把 BitSet 數(shù)據(jù)類型設(shè)計(jì)成用比特位的方式,就是為了節(jié)省內(nèi)存空間的同時能夠最大化表示出信息。那么,我們要迭代整個數(shù)據(jù)類型,一般來說就是按比特位搜尋,看哪些數(shù)位上是數(shù)字 1。如果是 1 的,那么對應(yīng)的編號就是我們要返回的結(jié)果;而如果對應(yīng)位是 0,那么就說明這個位置不是我們要搜索的數(shù)值,就得繼續(xù)移動游標(biāo)。

不過,我們總不能移動一次游標(biāo)就停止吧。比如說這個比特位序列是 010001,按照計(jì)算順序,我們先從最右側(cè)的 1 開始,但中間有 3 個 0,我們要取的是這兩個 1 的位置(即編號,因?yàn)?010001 的第 0 和第 4 個比特位是 1,所以我們就相當(dāng)于是把 0 和 4 作為結(jié)果進(jìn)行迭代),可如果 MoveNext 只移動一下游標(biāo)就退出的話,顯然是不夠的:因?yàn)橐苿拥街虚g 0 的位置的時候,這些 0 并不是合適的數(shù)據(jù),所以游標(biāo)會在這個時候繼續(xù)往下移動,直到碰到下一個 1 為止。那么,這個設(shè)計(jì)起來就比較復(fù)雜了:如果這個當(dāng)前游標(biāo)指向的比特位是 1,那么我們就算找到了合適的結(jié)果,那么 MoveNext 方法返回 true 作為結(jié)果即可;但是如果我們這個當(dāng)前游標(biāo)指向的比特位是 0 的話,那么就說明不是合適的數(shù)據(jù),就繼續(xù)往下移動游標(biāo),知道游標(biāo)指向了數(shù)字 1 為止;另外,如果在移動游標(biāo)的過程中超過了這個 BitSet 存儲的總?cè)萘浚?4 個比特)的話,也返回 false 作為結(jié)束,表示我無法繼續(xù)移動游標(biāo)了,象征迭代過程完全結(jié)束。

那么,寫出來的話,代碼就跟上面這個代碼是一樣的。

首先進(jìn)來就給 _index 字段增大一個單位??吹?jīng)]有,這就是為什么我們初始化的時候給 _index 字段設(shè)置 -1 的真正原因。因?yàn)?MoveNext 是剛開始必然會執(zhí)行的,所以初始化為 -1 是為了保證這里不出 bug。這里設(shè)置為 -1,那么 MoveNext 方法移動一次游標(biāo)直接讓 _index 字段從 0 開始,這才是符合邏輯的。

接著,判斷 _index 此時的數(shù)值是不是小于 MaxCapacity 常量(常量值是 64)。如果小于,我們就認(rèn)為我們迭代過程沒有超出整個 _mask 存儲的范疇,而 _index 此時充當(dāng)編號的角色,也可以認(rèn)為是位右移運(yùn)算的移動次數(shù)。如果 while 條件成立,我們就去始終循環(huán),看是否當(dāng)前這個 _index 上的比特位是不是 1。計(jì)算當(dāng)前位置的比特位是不是 1 我們用的是 _mask >> _index & 1 的這個公式。按照優(yōu)先級規(guī)則,我們是先計(jì)算 >>,然后是 &。先看 _mask >> _index,表示這個 _mask 位右移 _index 這么多個比特位,目的是把我們要找的這個比特位始終放在最后一位上去。接著,我們使用 & 1 計(jì)算這個比特位是不是 1。如果是 1,那么 1 & 1 才會得到 1;如果不是 1 而是 0 的話,就會得到 0 & 1 的結(jié)果 0。

此時,我們按照這個公式計(jì)算,當(dāng)前比特位是不是 1。如果是 1 的話,我們就認(rèn)為這個比特位是我們需要的結(jié)果,于是,我們返回 true 表示迭代是成功的。

如果 while 循環(huán)一輪走下來,都沒有找到 1,就說明遇到的數(shù)字全是 0,那么我們自然返回 false 就表示迭代結(jié)束,這樣就可以了。

那么,整個 Enumerator 數(shù)據(jù)類型的實(shí)現(xiàn)我們就算完成了。

3-4 使用

既然已經(jīng)實(shí)現(xiàn)了 Enumerator 類型,以及給 BitSet 配備了 GetEnumerator 方法,實(shí)現(xiàn)是正確的、合適的的話,我們就可以使用 foreach 循環(huán)了:

這個時候,我們寫的是 foreach (int element in b)。這里的 b 是表示 BitSet 的實(shí)例。那么這里為什么是 int 作為 foreach 每次迭代的變量類型呢?

Part 4 關(guān)于 foreach 的迭代變量類型

我們已經(jīng)實(shí)現(xiàn)了 foreach 循環(huán)可使用的兩種實(shí)現(xiàn)方式,一種是通過實(shí)現(xiàn)接口 IEnumerable 里的 GetEnumerator 方法來完成;另外一種則是通過自定義一個數(shù)據(jù)類型,然后完成迭代的操作。不過,可以看到 foreach 循環(huán)的迭代變量,類型是不一樣的,這是為什么呢?

這其實(shí)是取決于你實(shí)現(xiàn)的 GetEnumerator 方法,返回值的那個類型,它里面的 Current 到底是什么類型的。這句話有點(diǎn)繞也有點(diǎn)長,說白了,就是看這個 Current 屬性是什么類型,那么這個迭代變量就理應(yīng)是什么類型的。

可以看到,后面這個自己實(shí)現(xiàn)的類型里,Current 用的是 int 類型(畢竟里面的 _index 字段是 int 類型的),所以 foreach 循環(huán)里,我們用的是 int;而前面是通過接口的 GetEnumerator 方法實(shí)現(xiàn)的,但它為什么是 object 類型呢?

我剛才說過,是看 Current 屬性的類型。這個通過接口本身去實(shí)現(xiàn)的方式,我們是不是得去看 IEnumerator 接口里面的 Current 類型?。坑腥丝赡芫蜁?,我前面也沒提到 IEnumerator 里有 Current 屬性啊。你想想,我剛在 Part 3 完整闡述了自定義類型實(shí)現(xiàn) foreach 循環(huán)的迭代了,那么條件是不是應(yīng)該和原本使用 IEnumerable 接口實(shí)現(xiàn)的邏輯是一致的啊?既然是一致的,那么按常理來說,IEnumerable 接口里就必然有 GetEnumerator 方法,而 GetEnumerator 方法就必然返回 IEnumerator 接口,而 IEnumerator 接口和我們前面自己定義的 Enumerator 應(yīng)該就是異曲同工的設(shè)計(jì),里面就應(yīng)該包含 Current 屬性。

實(shí)際上,查閱文檔資料(網(wǎng)上查資料,或者直接去看元數(shù)據(jù)[1]),都可以看到,實(shí)際上確實(shí)包含這個 Current 方法,不過它的返回值是 object 類型的。正是因?yàn)槿绱?,我們最后使用接口?shí)現(xiàn)的 foreach 循環(huán)的方式,使用的是 object 類型作為迭代變量的類型。

[1]:元數(shù)據(jù)(Metadata),這個術(shù)語有點(diǎn)高大上。實(shí)際上,Visual Studio 提供了一個機(jī)制,讓我們在不看源代碼的情況下,查看庫里包含的這個數(shù)據(jù)類型,里面都有什么成員。查看方式是這樣的:首先,我們瞄準(zhǔn)我們書寫的代碼里的其中一個數(shù)據(jù)類型,比如鼠標(biāo)單擊 foreach (int element in list) 里的這個 int,然后按鍵盤 F12(或者點(diǎn)鼠標(biāo)右鍵,選擇“查看定義”,Visual Studio 的英文版里寫的是 Go to Definition),就可以進(jìn)入到元數(shù)據(jù)頁面了,然后你就可以查看到,這個數(shù)據(jù)類型里都有一些什么方法。按照這個方式,我們就可以查看到 IEnumerator 接口里是不是帶有 Current 屬性,并且是什么類型的。

光有這點(diǎn)語法內(nèi)容還不夠。因?yàn)槲覀兠看味贾苯訉?object 太麻煩了。所以 C# 的 foreach 循環(huán)是可以寫具體類型的,即使這個迭代的數(shù)據(jù)類型并不是它:

如代碼所示,我們知道里面是一個一個的 int 類型的元素,但我們因?yàn)橛玫氖?IEnumerable 接口里的 GetEnumerator 方法實(shí)現(xiàn)的行為,因此這里的類型原本必須是寫 object 的??蓡栴}在于,我們既然都知道里面是 int 的元素,那么每次都寫 object 的話,Console.WriteLine 方法里使用元素還得去強(qiáng)制轉(zhuǎn)換。所以,C# 提供了一個固有語法:如果這個類型可以使用 foreach 循環(huán)的話,那么這個迭代變量的數(shù)據(jù)類型可以取這個類型可以通過強(qiáng)制轉(zhuǎn)換或隱式轉(zhuǎn)換變化過去的那個類型。這句話的意思是,比如我 foreach 循環(huán)里的迭代變量的類型應(yīng)該是 Shape 類型的,那么我們在迭代變量的類型上可以改寫成 Shape 或者 Shape 自己的派生類型(比如 Circle 類型啊、Rectangle 類型啊這些)都是允許的;但跟 Shape 類型無關(guān)的別的數(shù)據(jù)類型是不行的,比如這個時候,因?yàn)榈愋褪?Shape,結(jié)果你用 int 類型去接收,就是不行的。

那么,我們就把 IEnumerable 接口給大家介紹了一下。那么接口使用的基本內(nèi)容就給大家介紹到這里。


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

分享到微博請遵守國家法律
长沙市| 江津市| 宝兴县| 中超| 淮阳县| 柏乡县| 鸡西市| 柳河县| 遵义市| 道孚县| 鄂温| 贵南县| 阿合奇县| 芜湖县| 吴川市| 福州市| 江门市| 汪清县| 博兴县| 冀州市| 水富县| 桂阳县| 乌拉特后旗| 顺昌县| 德州市| 华容县| 五大连池市| 思南县| 长汀县| 桓台县| 奉新县| 韶山市| 游戏| 常宁市| 陆川县| 乌拉特后旗| 旅游| 隆林| 昌黎县| 宁波市| 巴林左旗|