------- Windows Phone 7手機開發、.Net培訓、期待與您交流! -------
泛型引例ArrayList
相信大家在看楊中科老師基礎視頻中都不陌生個類ArrayList,我的基礎測試中也有關於這個類運用的一道題。可見泛型是很基礎同時又是很重要的一個知識點。ArrayList通用化是通過在類型與通用基類型Object之間進行強制轉換來實現的:添加到ArrayList中的任何引用或值類型都將隱式地向上強制轉換爲Object;如果項是值類型,則添加時需要進行裝箱操作,檢索時需要進行拆箱操作。
ArrayList通用化有2個主要缺點:強制轉換以及裝箱和拆箱操作都會降低性能(特別是大型集合時);另一個限制是缺少編譯時類型檢查,因爲所有項都強制轉換爲Object,所以在編譯時無法防止客戶端代碼執行非法操作。
using System;
using System.Collections;
namespace CSharpPractice.ArrayList
{
public class ArrayListTest
{
public static void Main()
{
//創建整型數組列表
ArrayList list1 = new ArrayList();
list1.Add(3);
list1.Add(105);
//顯示整型數組列表中的值
Console.WriteLine("整型數組列表ArrayList1的內容如下:");
foreach (int x in list1)
{
Console.WriteLine(x);
}
//創建字符串型數組列表
ArrayList list2 = new ArrayList();
list2.Add("Hello");
list2.Add("Friends");
//顯示字符串型數組列表中的值
Console.WriteLine("字符串型數組列表ArrayList2的內容如下:");
foreach (string s in list2)
{
Console.WriteLine(s);
}
//創建整數、字符串混合型數組列表
ArrayList list3 = new ArrayList();
list3.Add(11); // 添加一個整數.
list3.Add("字符串"); // 添加一個字符串
int t = 0;
// 求數組列表ArrayList3各元素之和
Console.WriteLine("數組列表ArrayList3各元素之和爲:");
foreach (int x in list3) // 產生運行時錯誤:InvalidCastException
{
t += x;
}
Console.ReadLine();
}
}
}
引例List<T>
與ArrayList相比,使用 List<T>時,必須爲每個實例指定其具體的數據類型。這樣將不再需要向上強制轉換爲System.Object以及裝箱和拆箱操作,同時也使得編譯器可以進行類型檢查,從而解決了ArrayList通用化的2個主要問題,保證了程序的性能和健壯性。
using System;
using System.Collections;
using System.Collections.Generic;
namespace CSharpPractice.ListT
{
public class ListTest
{
public static void Main()
{
//創建整型數組列表
List<int> list1 = new List<int>();
list1.Add(3);
list1.Add(105);
//顯示整型數組列表中的值
Console.WriteLine("整型數組列表ArrayList1的內容如下:");
foreach (int x in list1)
{
Console.WriteLine(x);
}
//創建字符串型數組列表
List<string> list2 = new List<string>();
list2.Add("Hello");
list2.Add("Friends");
//顯示字符串型數組列表中的值
Console.WriteLine("字符串型數組列表ArrayList2的內容如下:");
foreach (string s in list2)
{
Console.WriteLine(s);
}
// 試圖創建整數、字符串混合型數組列表,失敗!
List<int> list3 = new List<int>();
list3.Add(11); // 添加一個整數.
//list3.Add("字符串"); // 編譯錯誤
list3.Add(22); // 添加另一個整數.
int t = 0;
Console.WriteLine("數組列表ArrayList3各元素之和爲:");
foreach (int x in list3)
{
t += x;
}
Console.WriteLine(t);
Console.ReadLine();
}
}
}
一、泛型的概念與定義
泛型類似於 C++ 模板,通過泛型可以定義類型安全的數據結構,而無須使用實際的數據類型。例如,通過定義泛型方法(static void Swap<T>(ref T lhs, ref T rhs)),可以重用數據處理算法,實現不同類型數據(例如int、double)的交換,而無需分別爲int和double複製類型特定的代碼(重載方法),從而顯著提高性能並得到更高質量的代碼。.NET Framework 2.0版類庫提供一個新的命名空間 System.Collections.Generic,其中包含若干基於泛型的集合類。在泛型類的聲明中,需要聲明泛型參數,然後在泛型類的成員聲明中,使用該泛型參數作爲通用類型;而在創建泛型類的實例時,則需要與泛型參數對應的實際類型。
2.泛型類型參數
在泛型類型定義中,必須通過指定尖括號中的類型參數來聲明類型。類型參數實際上並不是特定類型,而只是類型佔位符。在創建泛型類型的實例時,必須指定尖括號中的類型(可以是編譯器識別的任何類型)
例如:
GenericList<float> list1 = new GenericList<float>();
GenericList<ExampleClass> list2 = new GenericList<ExampleClass>();
GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>();
類型參數遵循下列命名準則
使用“T”作爲描述性類型參數名的前綴,並使用描述性名稱命名泛型類型參數。
using System;
using System.Collections.Generic;
namespace CSharpPractice.Generic
{
public class GenericList<T>
{
// 嵌套類也通過泛型參數(<T>)定義.
private class Node
{ // T用於非泛型構造函數.
public Node(T t)
{
next = null;
data = t;
}
private Node next;
public Node Next
{
get { return next; }
set { next = value; }
}
// T作爲數據類型私有成員.
private T data;
// T作爲屬性返回類型.
public T Data
{
get { return data; }
set { data = value; }
}
}
private Node head;
public GenericList() // 構造函數
{ // 堆棧(後進先出)初始化
head = null;
}
// T作爲方法的參數類型:
public void AddHead(T t)
{ // 新結點加入到當前堆棧的頭部,並且成爲head
Node n = new Node(t);
n.Next = head;
head = n;
}
public IEnumerator<T> GetEnumerator()
{ // 從頭到尾依次輸出堆棧中的值
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}
class TestGenericList
{
static void Main()
{ // int是類型參數
GenericList<int> list = new GenericList<int>();
Console.WriteLine("0~9 十個整數形成堆棧");
for (int x = 0; x < 10; x++)
{ // 0~9 十個整數形成堆棧
list.AddHead(x);
}
Console.WriteLine("堆棧(後進先出)內容如下:");
foreach (int i in list)
{ // 輸出堆棧內容9~0
Console.Write(i + " ");
}
Console.ReadLine();
}
}
}
二、泛型接口
在泛型類的設計中,通常也把泛型類共通要實現的方法、委託或事件的簽名封裝爲泛型接口,然後在實現這些泛型接口的泛型類中實現這些方法等,下面是泛型接口示例。
using System;
using System.Collections.Generic;
namespace CSharpPractice.GenericInterface
{
class Program
{
static void Main()
{
int[] arr = { 0, 1, 2, 3, 4 };
List<int> list = new List<int>();
for (int x = 5; x < 10; x++)
{ // 形成列表 5、6、7、8、9
list.Add(x);
}
Console.WriteLine("輸出數組列表ArrayList的內容:");
ProcessItems<int>(arr);
Console.WriteLine("輸出列表List的內容:");
ProcessItems<int>(list);
Console.ReadLine();
}
static void ProcessItems<T>(IList<T> coll)
{
foreach (T item in coll)
{
Console.Write(item.ToString() + " ");
}
Console.WriteLine();
}
}
}
三、泛型方法
泛型方法是使用類型參數聲明的方法。編譯器能夠根據傳入的方法實參推斷類型形參。
using System;
namespace CSharpPractice.GenericMethod
{
public class GenericMethod
{
//聲明泛型方法:兩者交換
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
public static void Main()
{
int a = 1;
int b = 2;
Console.WriteLine("Original value, a = {0} , b = {1}", a, b);
//調用泛型方法:指定泛型參數的類型
Swap<int>(ref a, ref b);
Console.WriteLine("After swapping, a = {0} , b = {1}", a, b);
//調用泛型方法:可以省略類型參數,編譯器將推斷出該參數
double c = 1.1d;
double d = 2.2d;
Console.WriteLine("Original value, c = {0} , d = {1}", c, d);
Swap(ref c, ref d);
Console.WriteLine("After swapping, c = {0} , d = {1}", c, d);
Console.ReadLine();
}
}
}
四、泛型委託和泛型事件
通過泛型類型參數,同樣可以定義泛型委託。通過指定類型參數,可以引用泛型委託
在泛型類內部定義的委託,可以使用泛型類的泛型類型參數
基於泛型委託,可以定義泛型事件。此時發送方參數可以爲強類型,不再需要強制轉換成Object,或反向強制轉換,下面給出泛型委託和事件示例。
using System;
namespace CSharpPractice.GenericIntegrated
{
// 類型參數T使用尖括號< >括起.
public class GenericList<T> : System.Collections.Generic.IEnumerable<T>
{
protected Node head;
protected Node current = null;
// 嵌套類也是關於T的泛型類
protected class Node
{
public Node next;
private T data; // T作爲私有成員數據類型
public Node(T t) // T用於非泛化構造函數
{
next = null;
data = t;
}
public Node Next
{
get { return next; }
set { next = value; }
}
public T Data // T 作爲屬性的返回類型
{
get { return data; }
set { data = value; }
}
}
public GenericList() // 構造函數
{
head = null;
}
public void AddHead(T t) // T 作爲成員參數類型
{ //新結點加入到當前列表的頭部,並且成爲head
Node n = new Node(t);
n.Next = head;
head = n;
}
// Implementation of the iterator
public System.Collections.Generic.IEnumerator<T> GetEnumerator()
{ // 從頭到尾依次遍歷列表中每個節點
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
// IEnumerable<T>繼承自IEnumerable,所以該類必須同時實現
// GetEnumerator的泛型和非泛型方法。通常非泛型方法可以通過
// 直接調用泛型方法來簡化實現過程
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class SortedList<T> : GenericList<T> where T : System.IComparable<T>
{
// 一個簡單的、未經優化的排序算法:將列表元素從小到大排序
public void BubbleSort() // 冒泡排序
{
if (null == head || null == head.Next)
{
return;
}
bool swapped;
do
{
Node previous = null;
Node current = head;
swapped = false;
while (current.next != null)
{ // SortedList類在IEnumerable<T>上約束???
// Because we need to call this method, the SortedList
// class is constrained on IEnumerable<T>
if (current.Data.CompareTo(current.next.Data) > 0)
{
Node tmp = current.next;
current.next = current.next.next;
tmp.next = current;
if (previous == null)
{
head = tmp;
}
else
{
previous.next = tmp;
}
previous = tmp;
swapped = true;
}
else
{
previous = current;
current = current.next;
}
}
} while (swapped);
}
}
// 定義一個簡單的類Person來實現IComparable<T> ,
// 類Person本身作爲類型參數。
public class Person : System.IComparable<Person>
{
string name; // 姓名
int age; // 年齡
public Person(string s, int i)
{
name = s;
age = i;
}
// 對列表元素根據年齡排序.
public int CompareTo(Person p)
{
return age - p.age;
}
public override string ToString()
{
return name + ":" + age;
}
// 實現Equals方法,判斷兩個人是否同齡.
public bool Equals(Person p)
{
return (this.age == p.age);
}
}
class TestSortedList
{
static void Main()
{
// 聲明和實例化一個新的泛型SortedList類.
// Person 作爲類型參數.
SortedList<Person> list = new SortedList<Person>();
// 初始化Person對象,對name和age賦初值.
string[] names = new string[]
{
"劉一",
"陳二",
"張三",
"李四",
"王五",
"姚六",
};
int[] ages = new int[] { 45, 19, 28, 23, 18, 79 };
// 形成由name和age組成的列表.
for (int x = 0; x < 6; x++)
{
list.AddHead(new Person(names[x], ages[x]));
}
// 打印無序列表.
Console.WriteLine("初始(無序)列表爲:");
foreach (Person p in list)
{
Console.Write(p.ToString() + " ");
}
Console.WriteLine();
// 列表排序.
list.BubbleSort();
// 打印有序列表.
Console.WriteLine("\n按年齡排好序的列表爲:");
foreach (Person p in list)
{
Console.Write(p.ToString() + " ");
}
Console.ReadLine();
}
}
}
------- Windows Phone 7手機開發、.Net培訓、期待與您交流! -------