国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

C#集合 -- 自定義集合與代理

2019-11-17 03:12:26
字體:
來源:轉載
供稿:網友

C#集合 -- 自定義集合與代理

前面章節所討論的集合都可以直接實例化,因此我們可以非常方便地使用這些集合類。但是如果你試圖在集合添加或移除元素時添加控制,它們就不適用了。對于強類型集合,在某些情況下,你需要添加這樣的控制:

  • 添加或移除元素時,觸發事件
  • 更新由于添加或移除元素對應的屬性
  • 識別添加或刪除元素的誤操作并拋出異常

.NET Framework為上述目的提供了集合類,它們位于System.Collections.ObjectModel命名空間下。這些代理或包裝類類通過在擴展類實現所需的方法從而實現了ILIst<T>或IDictionary<TKey,TValue>類。每個Add,Remove和Clear操作都被標記為虛方法,從而當它們被重寫時可以充當一個入口的作用。

可自定義集合類通常都作為public的集合使用。比如,System.Windows.Form類中的集合控件。

Collection<T>類與CollectionBase類

image

Collection<T>是List<T>的可自定義的包裝器。

與IList<T>和IList實現一樣,它還定義了四個額外的虛方法和一個PRotected屬性

public class Collection<T>: IList<T>, IList, IReadOnlyList<T>    {        IList<T> items;              protected IList<T> Items {            get { return items; }        }        // ...               protected virtual void ClearItems() {            items.Clear();        }        protected virtual void InsertItem(int index, T item) {            items.Insert(index, item);        }                protected virtual void RemoveItem(int index) {            items.RemoveAt(index);        }        protected virtual void SetItem(int index, T item) {            items[index] = item;        }               //...    }

虛方法提供了一個入口,通過該入口,你可以勾住該入口以更改或增強默認的行為。而Items屬性允許實現者直接訪問“內部列表”--通過這種方式在內部實現變化而不觸發虛方法。

虛方法需要重寫;它們可以不用考慮直到有需求更改集合的默認行為。下面的例子演示了一個集合應有的“骨架”:

public class Animal{public string Name;public int Popularity;public Animal (string name, int popularity){Name = name; Popularity = popularity;}}public class AnimalCollection : Collection <Animal>{// AnimalCollection is already a fully functioning list of animals.// No extra code is required.}public class Zoo // The class that will expose AnimalCollection.{ // This would typically have additional members.public readonly AnimalCollection Animals = new AnimalCollection();}class Program{static void Main(){Zoo zoo = new Zoo();zoo.Animals.Add (new Animal ("Kangaroo", 10));zoo.Animals.Add (new Animal ("Mr Sea Lion", 20));foreach (Animal a in zoo.Animals) Console.WriteLine (a.Name);}}

AnimalCollection除了只是一個List<Animal>之外,沒有其他任何多余的功能;它的角色是為了將來的擴展需要。為了證實這點,現在我們需要添加Zoo屬性到Animal,從而AnimalCollection可以引用Zoo對象,從而表明Animal屬于哪個Zoo;并且AnimalCollection類重寫Collection<Animal>的每個虛方法以自動更新所影響的屬性。

public class Animal{public string Name;public int Popularity;public Zoo Zoo { get; internal set; }public Animal(string name, int popularity){Name = name; Popularity = popularity;}}public class AnimalCollection : Collection <Animal>{Zoo zoo;public AnimalCollection (Zoo zoo) { this.zoo = zoo; }protected override void InsertItem (int index, Animal item){base.InsertItem (index, item);item.Zoo = zoo;}protected override void SetItem (int index, Animal item){base.SetItem (index, item);item.Zoo = zoo;}protected override void RemoveItem (int index){this [index].Zoo = null;base.RemoveItem (index);}protected override void ClearItems(){foreach (Animal a in this) a.Zoo = null;base.ClearItems();}}public class Zoo{public readonly AnimalCollection Animals;public Zoo() { Animals = new AnimalCollection (this); }}

Collection<T>還有一個構造器方法,該方法接收IList<T>參數。與其他集合類不一樣,該集合是一個代理而不是一個備份,這就意味著后續的更改會直接反映到包裝的Collection<T>中(盡管并沒有觸發Collection<T>的虛方法)。相反,對COllection<T>所做的更改會影響到集合具體實現類。

CollectionBase

CollectionBase是非generic的Collection<T>,它在.NET Framework 1.0中就已經存在。它提供了與Collection<T>大多數功能,但是它使用起來非常笨拙。在CollectionBase類中,沒有IntertItem, RemoveITem, SetITem和ClearItem方法,取代它們的是OnInsert, OnInsertComplete, OnSet, OnSetComplete, OnRemove, OnRemoveComplete, OnClear和OnClearComplete方法。因為CollectionBase是非generic的,當你繼承該類時,你必須實現類型化的方法--至少,需要一個類型化的索引器和類型化的Add方法。

KeyedCollection<TKey,TItem>和DictionaryBase

image

KeyedCollection<TKey,TItem>繼承Collection<T>。它既添加又刪除了一些功能。添加的方法包括通過鍵獲取元素;刪除了內部列表的代理功能。

以鍵為基礎的集合與OrderedDictionary類相似,因為它使用一個哈希表構建了一個線性集合。但是,與OrderedDictionary不同,它并沒有實現IDictionary,因而不支持key/value對這樣的概念。鍵并不是從元素自身獲取,而是通過一個抽象的方法GetKeyFromItem。這就意味著遍歷這樣的以鍵為基礎的集合與遍歷一個普通的集合一樣。

Collection<TItem>加通過鍵快速查找的元素就是KeyedCollection<TKey,TItem>。

因為它繼承Collection<T>,一個鍵集合繼承了Collection<T>的所有功能,除了通過構造器設定一個內部集合實例。

Collection<T>的構造器如下:

public Collection() {    items = new List<T>();}public Collection(IList<T> list) {    if (list == null) {        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.list);    }    items = list;}

KeyedCollection的構造器如下:

protected KeyedCollection(): this(null, defaultThreshold) {}protected KeyedCollection(IEqualityComparer<TKey> comparer): this(comparer, defaultThreshold) {}protected KeyedCollection(IEqualityComparer<TKey> comparer, int dictionaryCreationThreshold) {    if (comparer == null) {         comparer = EqualityComparer<TKey>.Default;    }    if (dictionaryCreationThreshold == -1) {        dictionaryCreationThreshold = int.MaxValue;    }    if( dictionaryCreationThreshold < -1) {        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.dictionaryCreationThreshold, ExceptionResource.ArgumentOutOfRange_InvalidThreshold);    }    this.comparer = comparer;    this.threshold = dictionaryCreationThreshold;}

其他成員的定義如下面的代碼所示:

public abstract class KeyedCollection <TKey, TItem> : Collection <TItem>// ...protected abstract TKey GetKeyForItem(TItem item);protected void ChangeItemKey(TItem item, TKey newKey);// Fast lookup by key - this is in addition to lookup by index.public TItem this[TKey key] { get; }protected IDictionary<TKey, TItem> Dictionary { get; }}

GetKeyFromItem是抽象方法,由具體的實現類實現。當元素的鍵屬性發生變化時,必須調用ChangeItemKey方法,以更新內部的字典實例(Dictionary<TKey,TItem> dict;)。Dictionary屬性返回用于實現查詢的內部字典實例,該實例在向集合中插入第一個元素時自動創建。該行為可以通過構造器函數中的threshold參數來改變,如果執行了threshold,那么只有當達到臨界點之后,才會創建內部的字典實例。而不指定創建臨界點的好處是對于通過Dictionary屬性的Keys屬性,獲取ICollection的鍵而言,有一個有效的字典會非常有用。那么,該集合就可以作為一個公開的屬性傳遞給調用者。

使用KeyedCollection<>的場景是通過索引或者名字獲取集合元素。為了證實這點,請看下面的例子:

public class Animal{string name;public string Name{get { return name; }set {if (Zoo != null) Zoo.Animals.NotifyNameChange (this, value);name = value;}}public int Popularity;public Zoo Zoo { get; internal set; }public Animal (string name, int popularity){Name = name; Popularity = popularity;}}public class AnimalCollection : KeyedCollection <string, Animal>{Zoo zoo;public AnimalCollection (Zoo zoo) { this.zoo = zoo; }internal void NotifyNameChange (Animal a, string newName){this.ChangeItemKey (a, newName);}protected override string GetKeyForItem (Animal item){return item.Name;}// The following methods would be implemented as in the previous exampleprotected override void InsertItem (int index, Animal item)...protected override void SetItem (int index, Animal item)...protected override void RemoveItem (int index)...protected override void ClearItems()...}public class Zoo{public readonly AnimalCollection Animals;public Zoo() { Animals = new AnimalCollection (this); }}class Program{static void Main(){Zoo zoo = new Zoo();zoo.Animals.Add (new Animal ("Kangaroo", 10));zoo.Animals.Add (new Animal ("Mr Sea Lion", 20));Console.WriteLine (zoo.Animals [0].Popularity); // 10Console.WriteLine (zoo.Animals ["Mr Sea Lion"].Popularity); // 20zoo.Animals ["Kangaroo"].Name = "Mr Roo";Console.WriteLine (zoo.Animals ["Mr Roo"].Popularity); // 10}}

DictionaryBase

KeyedCollection的非generic的版本是DictionaryBase類。該歷史類的方法與之有很大不同。與CollectionBase一樣,它也是通過笨拙的鉤子方式實現了IDictionary,這些鉤子方法是:OnInsert, OnInsertComplete, OnSet, OnSetComplete, OnRemove, OnRem

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 仁化县| 轮台县| 高安市| 恭城| 漯河市| 天等县| 曲松县| 盐池县| 体育| 磐安县| 镇雄县| 嘉兴市| 新营市| 焦作市| 彩票| 文昌市| 兴义市| 小金县| 湖南省| 东乌珠穆沁旗| 永安市| 克山县| 错那县| 奉新县| 宣汉县| 东海县| 河北区| 嘉荫县| 池州市| 杂多县| 兴城市| 崇明县| 什邡市| 绿春县| 若尔盖县| 莱芜市| 白河县| 商都县| 万宁市| 繁峙县| 温泉县|