1、集合
數據有一定的限制,最不能忍受的是一旦創建,數組的大小就固定,不能再添加。而集合則包含了數組所具有的功能,且可以任意添加/刪減元素項,還有一些其他 功能。
集合的功能主要通過接口來實現,接口包含在System.Collections命名空間中。
主要有:
(1)System.Array類與System.Collections.ArrayList類
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.WriteLine("Create an Array type collection of Animal " + 6 "objects and use it:"); 7 Animal[] animalArray = new Animal[2]; 8 Cow myCow1 = new Cow("Deirdre"); 9 animalArray[0] = myCow1; 10 animalArray[1] = new Chicken("Ken"); 11 12 foreach (Animal myAnimal in animalArray) 13 { 14 Console.WriteLine("New {0} object added to Array collection, " + 15 "Name = {1}", myAnimal.ToString(), myAnimal.Name); 16 } 17 18 Console.WriteLine("Array collection contains {0} objects.", animalArray.Length); 19 animalArray[0].Feed(); 20 ((Chicken)animalArray[1]).LayEgg(); 21 Console.WriteLine(); 22 23 Console.WriteLine("Create an ArrayList type collection of Animal " + 24 "objects and use it:"); 25 ArrayList animalArrayList = new ArrayList(); 26 Cow myCow2 = new Cow("Hayley"); 27 animalArrayList.Add(myCow2); 28 animalArrayList.Add(new Chicken("Roy")); 29 30 foreach (Animal myAnimal in animalArrayList) 31 { 32 Console.WriteLine("New {0} object added to ArrayList collection," + 33 " Name = {1}", myAnimal.ToString(), myAnimal.Name); 34 } 35 Console.WriteLine("ArrayList collection contains {0} objects.", animalArrayList.Count); 36 ((Animal)animalArrayList[0]).Feed(); 37 ((Chicken)animalArrayList[1]).LayEgg(); 38 Console.WriteLine(); 39 40 Console.WriteLine("Additional manipulation of ArrayList:"); 41 animalArrayList.RemoveAt(0); 42 ((Animal)animalArrayList[0]).Feed(); 43 animalArrayList.AddRange(animalArray); 44 ((Chicken)animalArrayList[2]).LayEgg(); 45 Console.WriteLine("The animal called {0} is at index {1}.", 46 myCow1.Name, animalArrayList.IndexOf(myCow1)); 47 myCow1.Name = "Janice"; 48 Console.WriteLine("The animal is now called {0}.", 49 ((Animal)animalArrayList[1]).Name); 50 Console.ReadKey(); 51 } 52 }
System.Array類只能在初始化時固定數組大小,如:
Animal[] animalArray = new Animal[2];
而System.Collections.ArrayList類則是:
ArrayList animalArrayList = new ArrayList();//可以設置容量 ,但當超過時會自動增加一倍。
簡單數組Array中是強類型的,本例中是Animal類型,而ArrayList中則是System.Object。
System.Array類和ArrayList都實現了IEnumerable接口,因此可以在foreach中迭代。
(2)定義集合---創建自己的強類型化集合
一般情況是從一個類中派生自己的集合,例如System.Collections.CollectionBase類,這個抽象類提供了集合類的大量的實現代碼,包含了IEnumerable、ICollection、Ilist接口。
CollectionBase類提供了兩個受保護的屬性,可以訪問存儲對象本身。List可以通過IList接口訪問項,而InnerList則可用於存儲項的ArrayList對象。
1 public class Animals:CollectionBase 2 { 3 public void Add(Animal newAnimal) 4 { 5 List.Add(newAnimal); 6 } 7 public void Remove(Animal oldAnimal) 8 { 9 List.Remove(oldAnimal); 10 } 11 public Animals() 12 { 13 14 } 15 }
(3)索引符
上面定義的集合Animals是不能如animalCollection[0].Feed()這樣按照索引來訪問元素項的,必須使用索引符。
索引符其實是一種特殊類型的屬性,可添加在類中,提供類似於數組的訪問。
1 public Animal this[int animalIndex]//this關鍵字和後邊的方括號中的參數一起使用,如MyAnimals[0]。 2 { 3 get { return (Animal)List[animalIndex]; } 4 set { List[animalIndex] = value; } 5 }
小結:通過使用CollectionBase創建自己的強類型化集合集中了System.Array類的強類型化和System.Collections.ArrayList的多種項列表操作方法的優點,比較方便。但是內部還是發生了類型轉換。
(4)鍵控集合和IDictionary
類似於IList接口通過數字索引訪問項列表,IDictionary接口通過健值進行索引。同樣,也有一個基類實現了IDictionary接口,DictionaryBase。
1 public class Animals:DictionaryBase 2 { 3 public void Add(string newID,Animal newAnimal) 4 { 5 Dictionary.Add(newID, newAnimal); 6 } 7 public void Remove(string animalID) 8 { 9 Dictionary.Remove(animalID); 10 } 11 public Animals() 12 { } 13 14 public Animal this[string animalID] 15 { 16 get { return (Animal)Dictionary[animalID]; } 17 set { Dictionary[animalID] = value; } 18 } 19 }
但是基於DictionaryBase的集合和基於CollectionBase的集合之間還有一個區別是foreach的工作方式稍有區別。基於CollectionBase的集合可以從集合中直接提取Animal對象,而使用foreach和DictionaryBase的集合則需要提供DictionaryEntry結構才能得到類似的效果。
1 foreach (DictionaryEntry myEntry in animalCollection) 2 { 3 Console.WriteLine("New {0} object added to custom collection, " + 4 "Name = {1}", myEntry.Value.ToString(), ((Animal)myEntry.Value).Name); 5 }
(5) 迭代器
迭代器的定義是,它是一個代碼塊,按順序提供了要在foreach循環中使用的所有值。迭代器代碼塊的返回類型有兩種,IEnumerable和IEnumerator。
如果要迭代一個類,可使用方法GetEnumerator(),其返回類型是IEnumerator。
如果要迭代一個類成員,則使用IEnumerable。
這裡要使用yield關鍵字,但書上沒有詳細介紹。
(6)深度復制
所謂深度復制和淺度復制,在值類型上感覺是沒有區別的,都是復制一個值,而在引用類型上,淺度復制是復制對象的一個相同的引用,副本改變後則源也要改變。但是深度復制則不同,其復制對象的內容(包括字段等)而引用不同,副本發生變化時,源則不變。
2、比較
(1)類型比較
a. 封箱與拆箱
封箱是把值類型轉換為System.Object類型或者轉換為由值類型實現的接口類型。包含值類型變量的一個副本的引用。
拆箱是相反的過程。
封箱是在沒有用戶干涉的情況下進行的(即不需要編寫任何代碼),但是拆箱一個值需要進行顯式轉換,即需要類型轉換。
b. is運算符
is運算符並不是用來說明對象是某種類型,而是用來檢查對象是不是給定類型,或者是否可以轉換為給定類型,如果是,就返回true。
<operand> is <type>
(2)值比較
a. 運算符重載
要在類中重載運算符,必須給類添加運算符類型成員(使用operator關鍵字和運算符本身)且必須是static。
b. 使用IComparable和IComparer接口,該種方式廣泛用於集合類中。
一般使用IComparable給出類的默認比較代碼,使用其他類給出非默認的比較代碼。IComparable提供了一個方法CompareTo(),這個方法接受一個對象。IComparer也提供了一個Compare()方法。
最後,.Net Framework在類Comparer上提供了IComparer接口的默認實現方式,類Comparer位於System.Collections命名空間中,可以對簡單類型以及支持IComparable接口的任意類型進行特定文化的比較。
3、轉換
(1)重載轉換運算符
在代碼中,使用關鍵字implicit和explicit來指定轉換
1 public class ConvClass1 2 { 3 public int val; 4 public static implicit operator ConvClass2(ConvClass1 op1) 5 { 6 ConvClass2 returnVal = new ConvClass2(); 7 returnVal.val = op1.val; 8 return returnVal; 9 } 10 11 } 12 public class ConvClass2 13 { 14 public double val; 15 public static explicit operator ConvClass1(ConvClass2 op1) 16 { 17 ConvClass1 returnVal = new ConvClass1(); 18 returnVal.val = (int)(op1.val); 19 return returnVal; 20 } 21 }
(2) as運算符
使用下面的語法,把一種類型轉換為指定的引用類型。
<operand> as <type>
如果不能從<operand>轉換為<type>,則表達式的結果為null。