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。