久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

最佳實(shí)踐集合(轉(zhuǎn) MSDN)

 快樂學(xué)習(xí) 2007-11-22
部分計(jì)算機(jī)科學(xué)和編程的入門課本中都會(huì)有一章介紹集合,。它們可能被稱為數(shù)組或數(shù)據(jù)結(jié)構(gòu),但概念是相同的,。將正式數(shù)據(jù)對(duì)象中的一組元素與另一組元素聯(lián)系在一起的能力對(duì)現(xiàn)代編程技術(shù)來(lái)說(shuō)是必需的,。

 

在 Microsoft® .NET Framework 中,付出的很多努力都是為了創(chuàng)建強(qiáng)大的集合類,,以滿足各種需求及樣式,。這些集合使用方便、直觀,,并有足夠的性能,,這些都是非常重要的特征。在本月的這一期內(nèi)容中,,我將著眼于 .NET 中的集合,、它們的工作原理、使用它們的時(shí)機(jī)和一些最佳實(shí)踐,。


使用集合的時(shí)機(jī)

開發(fā)人員面對(duì)的第一個(gè)決定好像相當(dāng)簡(jiǎn)單:我是否該使用集合,?有時(shí)答案會(huì)顯而易見。有時(shí)候就是個(gè)人喜好問(wèn)題,。集合的基本用途是將某些對(duì)象聯(lián)系起來(lái)構(gòu)成一個(gè)組,,因?yàn)樗鼈儽舜碎g有著某種邏輯關(guān)系。例如,,您可以有一個(gè)代表書籍的 Book 類,,也可以有一個(gè)代表圖書館或圖書館中一書架書的 BookCollection 類。在這中情況下使用集合,,可以在書架中快速添加或刪除書籍,、移動(dòng)書籍、根據(jù)標(biāo)題或 ISBN 或某些其他描述性數(shù)據(jù)查找書籍,、統(tǒng)計(jì)書籍?dāng)?shù)量,、遍歷書籍等,。隨后我將就此詳細(xì)介紹,但在這種情況下使用集合是顯而易見的選擇,。

現(xiàn)在,,讓我們看一看您幾乎不會(huì)選擇使用集合的情形££有理數(shù)的情況。有理數(shù)是能表示為兩個(gè)整數(shù)之比的數(shù),。在集合描述中,,我提出集合應(yīng)該與一組元素結(jié)合使用,這樣您就可以使用有兩個(gè)元素的集合,,一個(gè)用做分子,,另一個(gè)用作分母。但是,,分子和分母的用途完全不同(與所有元素都用于相似目的的書籍示例不同),。在集合中存儲(chǔ)項(xiàng)目的一個(gè)主要原因是可以輕松遍歷所有元素,因此可以對(duì)每個(gè)元素進(jìn)行操作,,而對(duì)組成有理數(shù)的整數(shù)來(lái)說(shuō)這項(xiàng)任務(wù)幾乎沒有意義,。另外,有理數(shù)的元素?cái)?shù)量固定,,而且非常少,。因此,用集合存儲(chǔ)有理數(shù)的元素沒有任何意義,;這里您應(yīng)該使用兩個(gè)單獨(dú)的整數(shù)字段。

現(xiàn)在,,請(qǐng)?jiān)O(shè)想一個(gè)可能有必要討論使用集合的情形,。假設(shè)一個(gè)用于描述某個(gè)體育賽事(如棒球比賽)參賽隊(duì)的數(shù)據(jù)結(jié)構(gòu)。在比賽中需要對(duì)每個(gè)參賽隊(duì)執(zhí)行操作,,而且每個(gè)隊(duì)都有相似的目標(biāo)(與有理數(shù)中的分子和分母不同),。但是,在類似棒球這樣的比賽中,,只有兩個(gè)隊(duì)參賽,,因此雖然循環(huán)支持可能有用,但要枚舉的項(xiàng)目數(shù)量卻非常少(原型實(shí)現(xiàn)中數(shù)量是固定的),。有些人可能選擇使用 TeamCollection 或 Team 實(shí)例數(shù)組描述參賽雙方,,另外一些人可能選擇使用兩個(gè)單獨(dú)的 Team 字段。兩種實(shí)現(xiàn)各有其優(yōu)缺點(diǎn),。

然而,,考慮使用集合時(shí)應(yīng)牢記一些簡(jiǎn)單的指導(dǎo)方針。當(dāng)以下陳述至少有一個(gè)為真時(shí),,則應(yīng)該使用集合:

  • 各個(gè)元素具有相似的用途和同樣的重要性,。
  • 元素的數(shù)量未知,,或者沒有在編譯時(shí)固定。
  • 需要支持對(duì)所有元素的遍歷,。
  • 需要支持對(duì)元素的排序,。
  • 需要公開某個(gè)庫(kù)的元素,并且預(yù)期用戶在此使用集合類型,。

 

注意,,出于本欄目之目的,我認(rèn)為數(shù)組 (System.Array) 將成為一種特殊類型的集合,。


創(chuàng)建自定義集合的時(shí)機(jī)

.NET Framework 包含多種集合類型,,其中最常見的類型在 System.Collections 命名空間和子命名空間下(System.Array 除外)。我強(qiáng)烈建議在了解可用的集合后再編寫自定義集合,,因?yàn)楝F(xiàn)有的類型可以滿足您對(duì)集合的絕大部分需求,。

您可能需要?jiǎng)?chuàng)建自定義集合的情況是您在嘗試實(shí)現(xiàn) Framework 中尚不存在的特殊數(shù)據(jù)結(jié)構(gòu)。腦海中出現(xiàn)的圖形,、樹和其他特殊數(shù)據(jù)結(jié)構(gòu),。許多情況下它們會(huì)非常有用。如果需要現(xiàn)有集合類型的一個(gè)變體,,則必須創(chuàng)建一個(gè)自定義集合,。您可能需要集合只承載某些類型,并且此集合的特定實(shí)現(xiàn)取決于這些類型,。您可能出于性能考慮而需要自定義集合,;如果通用集合無(wú)法滿足您的特殊性能需求,編寫自定義集合可能是您的唯一選擇,。例如,,您可能需要一個(gè)能在其中快速插入項(xiàng)目的列表,同時(shí)也可以快速查找項(xiàng)目而不必遍歷該列表,。


現(xiàn)有的集合

如果您使用現(xiàn)有的集合,,則仍需要選擇合適的集合。根據(jù)構(gòu)建的內(nèi)容不同,,您可以從各種不同的集合中作出選擇,。首先,您需要確定集合中要存儲(chǔ)什么,,然后決定要如何使用集合,。是否會(huì)一次性添加所有元素?是否會(huì)動(dòng)態(tài)添加和刪除元素,?是否只需要遍歷整個(gè)集合,,或者還需要查找和使用特定元素?是否通過(guò)某個(gè)公共 API 公開集合?應(yīng)用程序的性能特征和要求是什么,?詢問(wèn)這些問(wèn)題有助于您決定使用哪個(gè)集合,,如果這些選項(xiàng)無(wú)法滿足您的需求,可以考慮擴(kuò)展集合而不是從頭開始,。


泛型或非泛型

.NET Framework 2.0 引入了泛型概念,。在 .NET Framework 1.x 中,大多數(shù)集合類都存儲(chǔ) System.Object 引用,。這意味著每次從集合中提取項(xiàng)目時(shí)都必須將其轉(zhuǎn)換回原來(lái)的類型(如果您建了庫(kù),,那么庫(kù)的使用者需要知道這些都是什么類型)。這個(gè)轉(zhuǎn)換對(duì)性能有影響,,尤其在存儲(chǔ)值類型時(shí),,因?yàn)閷⒅堤砑拥郊蠒r(shí)首先需要將值封裝到 System.Object 中,以后在從集合中取出值并轉(zhuǎn)換回原來(lái)的類型時(shí)需要取消封裝,。

通過(guò)使用泛型集合類型(可在 System.Collections.Generic 命名空間下找到),,可以避免這些問(wèn)題。例如,,如果您的 C# 應(yīng)用程序中需要一個(gè)字符串列表,,則可以使用 System.Collections.Generic.List<String>(Visual Basic® 中為 List(Of String),C++ 中為 <String^>),。這樣可以確保提取元素時(shí),,它們只進(jìn)入 System.String 類型(意味著您不需要從 Object 轉(zhuǎn)換到 String)。如果嘗試在列表中存儲(chǔ)其他內(nèi)容,,也可以通過(guò)提供編譯時(shí)錯(cuò)誤使編譯器強(qiáng)制該行為,。另外,如果您正在開發(fā)供其他人使用的庫(kù),,并且不知道他們要使用什么內(nèi)含類型,,則可以繼續(xù)使用庫(kù)用戶隨后將定義的泛型 T。您也可以限制該 T 類型,,以便對(duì)即將使用的類型有些了解(它們從一組特定的接口派生而來(lái),它們實(shí)現(xiàn)無(wú)參數(shù)的構(gòu)造函數(shù),,等等),。

如果您現(xiàn)在或?qū)?lái)使用 .NET Framework 2.0,非常不鼓勵(lì)使用舊的非泛型集合,。需要保存它們的唯一原因可能是作為遺產(chǎn),,或者您的代碼需要與舊版的 Framework 配合使用。使用舊的非泛型集合會(huì)降低代碼速度,,也會(huì)降低它的可讀性,。即使需要在一個(gè)集合中存儲(chǔ)多個(gè)類型,仍可使用泛型集合。您只需要為要存儲(chǔ)的對(duì)象找到一個(gè)常用的基本類型,;最不濟(jì)也可以將 System.Object 用作泛型參數(shù)以便存儲(chǔ)任何內(nèi)容(如 List<Object>),,因?yàn)槊總€(gè)類型都是從 System.Object 派生而來(lái)。

如果有使用非泛型集合的舊代碼,,強(qiáng)烈建議您考慮更改代碼以便使用泛型集合,。圖 1 中的表顯示了建議的類型和應(yīng)使用的接口。此外,,.NET Framework 2.0 還包含了在 .NET Framework 1.x 中沒有直接對(duì)應(yīng)項(xiàng)的新泛型集合,,例如,LinkedList<T> 和 SortedDictionary<TKey, TValue>,。.NET Framework 3.5 還包含一個(gè) HashSet<T> 類,,提供新的標(biāo)準(zhǔn)集功能(先前的版本中,通??衫?Hashtable 或 Dictionary<TKey,TValue> 來(lái)滿足對(duì)集的需求),。


性能方面的含義

需要集合的設(shè)計(jì)通常是因?yàn)樾枰褂么罅康捻?xiàng)目,而您使用的項(xiàng)目數(shù)量會(huì)影響應(yīng)用程序的性能,。要確保選擇了正確的集合類型,,重要的是了解預(yù)期的集合使用模式。例如,,您可能只在初始化應(yīng)用程序時(shí)在集合中插入項(xiàng)目,,或者在程序的整個(gè)生命周期中您都可能插入項(xiàng)目。您與集合的唯一交互可能是遍歷所有元素,,或者您可能需要隨機(jī)訪問(wèn)功能,。了解使用配置文件有助于找到符合需求的最佳集合。

如果需要非??斓靥砑?、刪除和查找項(xiàng)目,而且不關(guān)心集合中項(xiàng)目的順序,,那么首先應(yīng)該考慮使用 System.Collections.Generic.Dictionary<TKey, TValue>(或者您正在使用 .NET Framework 1.x,,可以考慮 Hashtable)。三個(gè)基本操作(添加,、刪除和包含)都可快速操作,,即使集合包含上百萬(wàn)的項(xiàng)目。另一方面,,利用 List<T>(或 .NET Framework 1.x 中的 ArrayList)插入和刪除項(xiàng)目所需的時(shí)間都可能有所不同,。(List<T> 和 ArrayList 都在基礎(chǔ)數(shù)組中存儲(chǔ)項(xiàng)目,并保持順序,。添加項(xiàng)目可能需要移動(dòng)基礎(chǔ)數(shù)組中現(xiàn)有的項(xiàng)目以騰出空間,。在末尾添加項(xiàng)目不需要進(jìn)行任何移動(dòng),,而且速度非常快),。

如果您的使用模式很少需要?jiǎng)h除和大量添加,,而重要的是保持集合的順序,那么您仍然可以選擇 List<T>,。雖然查找速度可能比較慢(因?yàn)樵谒阉髂繕?biāo)項(xiàng)目時(shí)需要遍歷基礎(chǔ)數(shù)組),,但可以保證集合會(huì)保持特定的順序。另外,,您可以選擇 Queue<T> 實(shí)現(xiàn)先進(jìn)先出 (FIFO) 順序或 Stack<T> 實(shí)現(xiàn)后進(jìn)先出 (LIFO) 順序,。雖然 Queue<T> 和 Stack<T> 都支持枚舉集合中的所有項(xiàng)目,但前者只支持在末尾插入和從開頭刪除,,而后者只支持從開頭插入和刪除,。

如果需要在實(shí)現(xiàn)快速插入的同時(shí)保持順序,那么使用新的 LinkedList<T> 集合可幫助您提高性能,。與 List<T> 不同,,LinkedList<T> 是作為動(dòng)態(tài)分配的對(duì)象鏈實(shí)現(xiàn)。與 List<T> 相比,,在集合中間插入對(duì)象只需要更新兩個(gè)連接和添加新項(xiàng)目,。從性能的角度來(lái)看,鏈接列表的缺點(diǎn)是垃圾收集器會(huì)增加其活動(dòng),,因?yàn)樗仨毐闅v整個(gè)列表以確保沒有對(duì)象沒有被釋放,。另外,由于每個(gè)節(jié)點(diǎn)相關(guān)的開銷以及每個(gè)節(jié)點(diǎn)在內(nèi)存中的位置等原因,,大的鏈接列表可能會(huì)出現(xiàn)性能問(wèn)題,。雖然將項(xiàng)目插入到 LinkedList<T> 的實(shí)際操作比在 List<T> 中插入要快得多,但是找到要插入新值的特定位置仍需遍歷列表并找到正確的位置,。

如前所述,,Dictionary<TKey, TValue> 可能最適用于快速插入和查找項(xiàng)目。但是,,較快的查找速度只是針對(duì)普通情況而言,,某些數(shù)據(jù)集可能導(dǎo)致性能急劇下降。SortedDictionary<TKey,TValue> 是一個(gè)不同的實(shí)現(xiàn),,它用平衡樹實(shí)現(xiàn)作為基礎(chǔ)數(shù)據(jù)存儲(chǔ),;這相對(duì)提高了查找速度并保持項(xiàng)目的排列順序,但插入很有可能會(huì)慢一些(隨集合中的項(xiàng)目數(shù)量不同而有所差異),。或者也可以用 SortedList<Tkey,TValue>,,它使用兩個(gè)獨(dú)立的數(shù)組分別保存鍵和值,,并保持兩者的順序(最壞的情況是必須移動(dòng)所有鍵和值)。


使用 List<T> 的天氣年鑒

以下示例是一個(gè)簡(jiǎn)單的應(yīng)用程序,計(jì)算各城市天氣預(yù)報(bào)列表的平均溫度和濕度(請(qǐng)參見圖 2),。WeatherReport 類用于存儲(chǔ)所選城市的單個(gè)天氣事件,。List<WeatherReport> 集合用于存儲(chǔ)求平均值的信息。我在這個(gè)案例中選擇了 List<T> 集合,,因?yàn)槲业氖褂媚J绞侵惶砑禹?xiàng)目,,而不是刪除項(xiàng)目。另外,,我不關(guān)心排序或在中間插入項(xiàng)目,,也不關(guān)心在列表中查找單個(gè)項(xiàng)目。我對(duì)列表做的唯一其他操作是遍歷項(xiàng)目,。您可以選擇將此程序擴(kuò)展為找到最熱或最冷的城市,,以及增加許多天氣年鑒類型操作。


自定義集合

某些情況下,,您可能發(fā)現(xiàn) Framework 中任何現(xiàn)有的集合類型都無(wú)法滿足您的全部要求,。可能您有獨(dú)特的要求,,或者仍在使用經(jīng)過(guò)很少改動(dòng)的現(xiàn)有集合,。如果決定要編寫自定義集合,首先要考慮擴(kuò)展現(xiàn)有的集合類型,。

通過(guò)查看 System.Collections.ObjectModel 命名空間開始,。這些集合已經(jīng)實(shí)現(xiàn)了最需要的接口,并為您提供了需要的基本功能,。您可以輕易地為繼承的類添加方法,,從而滿足您的特定需求。

例如,,假設(shè)您需要實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 System.Double 值集合,,但還希望支持使用 Double.TryParse 的 Add(string) 方法,只在將值成功解析為 Double 后才添加結(jié)果,。System.Collections.ObjectModel.Collection<T> 類實(shí)現(xiàn)了所有的標(biāo)準(zhǔn)集合接口,,為了提供附加的 Add 重載,您的自定義集合類型從 Collection<Double> 派生即可,。

class DoubleCollection : Collection<double>
{
public void Add(string st)
{
Double d;
if (Double.TryParse(st, out d)) base.Add(d);
else throw new ArgumentException(
“Cannot parse string to a double. “ +
“Item was not added to collection.”);
}
}

 

隨著擴(kuò)展方法的引入,,.NET Framework 3.5 可以提供額外的機(jī)制來(lái)創(chuàng)建擴(kuò)展現(xiàn)有類型的方法。例如,,您可以在 C# 3.0 中重新編寫此方法作為擴(kuò)展方法,,如下所示:

class CollectionExtensions
{
public static void Add(this Collection<Double> c, string st)
{
Double d;
if (Double.TryParse(st, out d)) c.Add(d);
else throw new ArgumentException(
“Cannot parse string to a double. “ +
“Item was not added to collection.”);
}
}

 

如果一個(gè) Collection<Double> 有命名的值,則此靜態(tài)方法可通過(guò)傳統(tǒng)語(yǔ)法將新值添加到集合中,。

CollectionExtensions.Add(values, “3.14”);

 

但是,,因?yàn)檫@是一個(gè)擴(kuò)展方法(顯然“this”關(guān)鍵字將第一個(gè)參數(shù)歸為靜態(tài) Add 方法),,您可以按如下所示重新編寫:

values.Add(“3.14”);

 

如果用新類型擴(kuò)展了 Collection<Double>,那么您會(huì)編寫完全相同的方法調(diào)用,,但您現(xiàn)在可以將此新 Add 方法與任何 Collection<Double> 實(shí)例(或其派生的任何類型)配合使用,,而不只是與自定義類型一起使用?;蛘吣梢蚤_始構(gòu)建自己的集合,,不需要繼承任何現(xiàn)有的集合。這種情況下,,您可以利用 .NET Framework 中提供的適當(dāng)接口,。


實(shí)現(xiàn)集合接口

如果您真的決定從頭開始編寫自己的自定義集合,則應(yīng)實(shí)現(xiàn) .NET Framework 提供的所有適當(dāng)接口,。這些接口公開了與集合交互的常見方式,,大多數(shù)人都認(rèn)為非常直觀和易于使用。下面是可供選擇的各種接口的簡(jiǎn)短概述,。

IEnumerable  該接口允許通過(guò)返回集合枚舉器來(lái)枚舉集合,。該接口公開可返回 IEnumerator 對(duì)象的單一方法 GetEnumerator。IEnumerator 對(duì)象用于快速遍歷整個(gè)集合,。實(shí)現(xiàn)了此接口的任何集合都可以通過(guò) C# 中的 foreach 語(yǔ)言結(jié)構(gòu)(在 Visual Basic 中是 For Each)進(jìn)行訪問(wèn),。

IEnumerable<T>  此接口通過(guò)附加的 GetEnumerator 方法擴(kuò)展了非泛型 IEnumerable,該方法返回 IEnumerator<T> 而不是 IEnumerator,。這意味著如果計(jì)劃實(shí)現(xiàn) IEnumerable<T>,,則還必須實(shí)現(xiàn) IEnumerable。不同之處是此附加的 GetEnumerator 返回泛型版本的 IEnumerator (IEnumerator<T>) 而不是非泛型版本,。這是一個(gè)常見的做法,,首先在 IEnumerable<T> 中提供集合的枚舉邏輯,然后使非泛型 GetEnumerator 方法委托到泛型 GetEnumerator 方法以確保兩者都返回相同的枚舉器(從而不需要再一次實(shí)現(xiàn)同一邏輯),。

IEnumerator  此接口通常不由集合自身實(shí)現(xiàn),。我在此提到它是因?yàn)樗且粋€(gè)有用的接口,在構(gòu)建自定義集合時(shí)應(yīng)牢記,。此接口用于枚舉集合中的項(xiàng)目,。它公開三個(gè)方法:Reset、Current 和 MoveNext,。Reset 方法用于初始化枚舉,。Current 方法用于獲取當(dāng)前的項(xiàng)目,MoveNext 用于移至下一個(gè)項(xiàng)目,。如果能用 GetEnumerator 為集合獲取一個(gè)枚舉器,,則可以實(shí)現(xiàn) foreach 循環(huán)。例如,,如果 Words 是一個(gè)字符串 ArrayList,,那么以下代碼將得到相同結(jié)果:

foreach (string word in Words)  Console.WriteLine (word);

 

IEnumerator enumerator = Words.GetEnumerator();
while(enumerator.MoveNext())
Console.WriteLine(enumerator.Current);

 

IEnumerator <T>  泛型版本的 IEnumerator 接口通過(guò)添加返回 T 的 Current 屬性重載擴(kuò)展了非泛型版本,。此重載無(wú)需進(jìn)行轉(zhuǎn)換,從而使枚舉集合更簡(jiǎn)單,。

ICollection  此接口是 IEnumerable 的擴(kuò)展。它還公開三個(gè)附加的屬性和一個(gè)附加的方法:Count 是一個(gè)只讀屬性,,可返回集合中的元素?cái)?shù)量,;IsSynchronized 指出該集合對(duì)線程安全,因此可以在多線程應(yīng)用程序中使用它,;SyncRoot 使實(shí)現(xiàn)人員能夠?qū)崿F(xiàn)對(duì)線程安全的集合(通過(guò)提供用于該目的的對(duì)象),;CopyTo 用于將集合的項(xiàng)目按給定索引復(fù)制到數(shù)組。大體來(lái)說(shuō),,我建議避免使用非泛型 ICollection 接口,,因?yàn)榉盒徒涌谝杏玫枚唷?/p>

ICollection<T>  此接口是 IEnumerable<T> 的擴(kuò)展(因此也是 IEnumerable 的擴(kuò)展接口)。它還公開五個(gè)新方法和兩個(gè)新屬性,。方法包括 Add(用于將新元素添加到集合中),、Remove(用于刪除元素)、Clear(用于刪除所有元素),、Contains(用于確定某個(gè)項(xiàng)目是否在集合中)和 CopyTo(用于將項(xiàng)目復(fù)制到數(shù)組),。兩個(gè)只讀屬性是 Count(與非泛型 ICollection 中的相同)和 IsReadOnly,后者告訴我們集合是否為只讀,,或者說(shuō)無(wú)法刪除或添加項(xiàng)目(即使集合為只讀,,集合中的可變項(xiàng)目仍然可以更改)。

此接口作為任何自定義集合的起點(diǎn)都非常有用,。如果不知道要在集合中存儲(chǔ)什么類型的項(xiàng)目(或要存儲(chǔ)多種類型的項(xiàng)目),,用 ICollection<Object> 即可,實(shí)際上得到的是非泛型的擴(kuò)展 ICollection 接口,。

IList 和 IList<T>  IList 是 ICollection 的擴(kuò)展,。除了 ICollection(泛型或非泛型版本)中的所有內(nèi)容外,它還有 IndexOf,、Insert 和 RemoveAt 方法以及一個(gè)索引器,,用于獲取和設(shè)置集合中的任何項(xiàng)目,就如同使用數(shù)組一樣,。非泛型 IList 也包含存在于泛型 ICollection 中和不存在于非泛型 ICollection 中的方法(Add,、Remove、Clear 和 Contains),。創(chuàng)建自定義集合時(shí) IList 接口非常有用,,可用于自行添加和刪除項(xiàng)目,獲取或設(shè)置任何項(xiàng)目的值,。RemoveAt 方法可根據(jù)索引刪除項(xiàng)目(而常規(guī) Remove 只能根據(jù)值刪除項(xiàng)目),。Insert 方法用于在列表的任何位置添加項(xiàng)目,,而常規(guī) Add 只能在最后添加。

IDictionary 和 IDictionary<TKey, TValue>  IDictionary 是 ICollection 的擴(kuò)展,。它支持用一個(gè)鍵在集合中存儲(chǔ)和查找項(xiàng)目的概念,。除了 ICollection 支持的所有方法外,它還公開了將鍵與添加的項(xiàng)目相關(guān)聯(lián)的另一個(gè) Add 重載,。ContainsKey 方法將檢查是否存在特殊鍵,。Keys 和 Values 屬性可返回 IDictionary 中所有鍵或值的 ICollection、基于鍵而不是值的刪除重載,,以及使用該鍵的索引器,。該接口的泛型版本要復(fù)雜一些,因?yàn)樗试S分別指定值類型和鍵類型,。


再次強(qiáng)調(diào)泛型或非泛型

創(chuàng)建自定義集合時(shí),,可能不必使之成為泛型。如果知道集合要存儲(chǔ)的對(duì)象類型,,而且知道這些類型將來(lái)不會(huì)改變,,則可使用固定類型的集合。您仍可以擴(kuò)展泛型框架集合或使用泛型接口,,但類總會(huì)存儲(chǔ)特定類型的對(duì)象,。

如果您要構(gòu)建庫(kù)或更通用的集合(如樹或圖),那么創(chuàng)建泛型可能是一個(gè)不錯(cuò)的主意,。這樣此類型的使用者就能夠?qū)⑺c各種類型一起使用,,而且沒有使用 Object 和來(lái)回轉(zhuǎn)換的缺點(diǎn)。通用有向圖類可能如下所示:

class DirectionalGraph<T> :
IEnumerable<T>, ICollection<T>, IList<T>
{
public void Clear() { }
public void Add(T item, IEnumerable<T> inNodes,
IEnumerable<T> outNodes) { }
public void Remove(T item) { }
public bool Contains(T item) { }
static public DirectionalGraph<T> EmptyGraph { get{}}
// implement the interfaces...
}

 


家族樹

下一個(gè)示例中,,我將實(shí)現(xiàn)一個(gè)自定義的集合來(lái)存儲(chǔ)用于家譜目的的家族樹(請(qǐng)參見圖 3),。為簡(jiǎn)化起見,我將做如下假設(shè):每個(gè)人都有性別和年齡,,每個(gè)人都有生父母,。讓我們稱他們?yōu)槟赣H和父親。

樹是由節(jié)點(diǎn)構(gòu)成的特殊集合類型,。每個(gè)節(jié)點(diǎn)(如圖 4 中的 Person 類)都存儲(chǔ)著有關(guān)樹中其他節(jié)點(diǎn)的信息,。有一個(gè)特殊的節(jié)點(diǎn)被稱為“根”,它是樹的基礎(chǔ),。所有其他節(jié)點(diǎn)都可以從樹的根節(jié)點(diǎn)開始遍歷訪問(wèn),。我還實(shí)現(xiàn)了 IEnumerable<T>,通過(guò) foreach 循環(huán)枚舉 FamilyTree 的所有成員,。所有人員都輸入到樹中后,,您應(yīng)該能夠回答如下問(wèn)題:A 和 B 兩個(gè)人之間是什么關(guān)系?

注意,此示例中并沒有實(shí)現(xiàn)所有可能的關(guān)系,,但您可以自己向 FindRelationship 方法添加更多的關(guān)系,。另外還需要注意,為了示例的清晰起見,,并沒有對(duì)所有方法都進(jìn)行充分的參數(shù)檢驗(yàn),。建議您在實(shí)現(xiàn)之前確保每個(gè)方法只接受有效的參數(shù)值。

在運(yùn)行圖 5 中的示例時(shí),,應(yīng)該注意圖 6 中顯示的輸出,。

圖 6 家族樹輸出示例
圖 6 家族樹輸出示例  (單擊該圖像獲得較大視圖)

此刻您應(yīng)該對(duì) .NET Framework 中的集合、它們是什么,,以及使用它們的時(shí)機(jī)和原因有了很好的理解。集合可以是編程工具箱中的強(qiáng)大工具,,因此了解它何時(shí)有用以及如何聰明地使用它都非常重要,。如果您需要更多的信息,請(qǐng)參閱“更多參考資料”側(cè)欄中的資源,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多