C#知識 泛型
C#知識 泛型
泛型是 2.0 版 C# 語言和公共語言運行庫 (CLR) 中的一個新功能。泛型將類型參數的概念引入 .NET Framework,類型參數使得設計如下類和方法成為可能:這些類和方法將一個或多個類型的指定推遲到客戶端代碼聲明並實例化該類或方法的時候。例如,通過使用泛型類型參數 T,您可以編寫其他客戶端代碼能夠使用的單個類,而不致引入運行時強制轉換或裝箱操作的成本或風險,避免進行強制類型轉換的需求提高類型安全性。
泛型概述及優點
泛型類和泛型方法同時具備可重用性、類型安全和效率高等特點。它通常用在集合和在集合上運行的方法中。.NET 2.0版類庫提供了一個新的名為System.Collections.Generic的命名空間,其中包含幾個新的基於泛型的集合類。
也可以創建自定義泛型類型和方法。
泛型類和方法接收”類型參數“,指定了要操作的對象的類型:
public class Test {}
在實例化時才指定類型。
Test tree = new Test();
使用泛型類型有以下優點:
使用泛型類型可以最大限度地重用代碼、保護類型的安全以及提高性能。泛型最常見的用途是創建集合類。.NET Framework 類庫在 System.Collections.Generic 命名空間中包含幾個新的泛型集合類。應盡可能地使用這些類來代替普通的類,如 System.Collections 命名空間中的 ArrayList。您可以創建自己的泛型接口、泛型類、泛型方法、泛型事件和泛型委托。可以對泛型類進行約束以訪問特定數據類型的方法。關於泛型數據類型中使用的類型的信息可在運行時通過反射獲取。
泛型中的類型參數T
類型參數T用來定義泛型類時的占位符,並不是一種類型,僅代表某種可能的類型。在定義時,T出現的位置可以在使用是用任何類型來代替。
決定在何時何地使用泛型
您需要考慮以下幾件事件:
您所使用的類型是否包含或操作未指定的數據類型(如集合類型)?如果是這樣,創建泛型類型將能提供更多的好處。如果您的類型只操作單一的指定類型,那麼就沒有必要去創建一個泛型類。 如果您的類型將操作值類型,那麼就會產生裝箱和拆箱操作,就應該考慮使用泛型來防止裝箱和拆箱操作。 泛型的強類型檢查有助於快速查找錯誤(也就是編譯期而非運行期),從而縮短bug修復周期。在編寫多個類操作多個數據類型時是否遭遇到“代碼膨脹”問題(如一個ArrayList只存儲StreamReaders而另一個存儲StreamWriters)?其實編寫一次代碼並讓它工作於多個數據類型非常簡單。泛型使得代碼更為清晰。通過消除代碼膨脹並進行強制檢查,您的代碼將變得更易於閱讀和理解。
針對類的泛型
針對不同類型的數組,寫一個針對數組的”冒泡排序“。
思路
針對類的泛型,泛型打在類旁。由於在”冒泡排序“中需要對元素進行比較,所以泛型要約束成實現IComparable接口。
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
SortHelper isorter = new SortHelper();
int[] iarray = { 8, 7, 1, 2, 12 };
isorter.BubbleSort(iarray);
foreach (int item in iarray)
{
Console.Write(item + ",");
}
Console.ReadKey();
}
}
public class SortHelper where T : IComparable
{
public void BubbleSort(T[] array)
{
int length = array.Length;
for (int i = 0; i <= length - 2; i++)
{
for (int j = length - 1; j >= 1; j--)
{
if (array[j].CompareTo(array[j - 1]) < 0)
{
T temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}
}
}
輸出:
關於泛型約束
where T : IComparable 把T約束為實現IComparable接口 where T : class where T : struct where T : IComparable, new() 約束泛型必須有構造函數
關於冒泡算法
之所以for (int i = 0; i <= length -2; i++),這是邊界思維,比如有一個長度為5的數組,如果0號位元素最終調換到4號位,每次調一個位,需要經過4次才能到4號位,即for(int i = 0; i <= 5-2, i++),i依次為0, 1, 2, 4,期間經歷了4次。至於fZ喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vciAoaW50IGogPSBsZW5ndGggLSAxOyBqID49IDE7IGotLSnRrbu3o6y8tLHpwPq009fuuvPSu7j21KrL2L+qyry1vcv30v3OqjG1xNSqy9ijrMO/tM7T68ew0ru49s671sPJz7XE1KrL2LHIvc+howoKCjxoMz652NPasci9zzwvaDM+CiAgICAgICAgaW50IMDg0M3Wrsv50tTE3LHIvc+jrMrH0vLOqmludMDg0M3Ktc/WwctJQ29tcGFyYWJsZb3Tv9qho2J5dGXA4NDN0rLSu9H5oaMKPGgyPtfUtqjS5dK7uPbA4KOsyrnWrtKyxNzKtc/Ww7DF3cvjt6g8L2gyPgogICAgICAgIMOwxd3L47eoyea8sLW91KrL2LHIvc+jrMv50tTX1Lao0uXA4LHY0OvKtc/WSUNvbXBhcmFibGW907/aoaMKPHByZSBjbGFzcz0="brush:java;">namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Book[] bookArray = new Book[2];
Book book1 = new Book(100, "書一");
Book book2 = new Book(80, "書二");
bookArray[0] = book1;
bookArray[1] = book2;
Console.WriteLine("冒泡之前:");
foreach (Book b in bookArray)
{
Console.WriteLine("書名:{0},價格:{1}", b.Title, b.Price);
}
SortHelper
sorter = new SortHelper();
sorter.BubbleSort(bookArray);
Console.WriteLine("冒泡之後:");
foreach (Book b in bookArray)
{
Console.WriteLine("書名:{0},價格:{1}", b.Title, b.Price);
}
Console.ReadKey();
}
}
public class SortHelper where T : IComparable
{
public void BubbleSort(T[] array)
{
int length = array.Length;
for (int i = 0; i <= length - 2; i++)
{
for (int j = length - 1; j >= 1; j--)
{
if (array[j].CompareTo(array[j - 1]) < 0)
{
T temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}
}
//自定義實現IComparable接口
public class Book : IComparable
{
private int price;
private string title;
public Book(){ }
public Book(int price, string title)
{
this.price = price;
this.title = title;
}
public int Price
{
get
{
return this.price;
}
}
public string Title
{
get
{
return this.title;
}
}
public int CompareTo(object obj)
{
Book book = (Book)obj;
return this.Price.CompareTo(book.Price);
}
}
} 輸出:
針對方法的泛型
繼續上面的例子,自定義一個類,並定義泛型方法。
namespace ConsoleApplication1
{
// 方法泛型
public class MethodSortHelper
{
public void BubbleSort(T[] array) where T : IComparable
{
int length = array.Length;
for (int i = 0; i <= length - 2; i++)
{
for (int j = length - 1; j >= 1; j--)
{
if (array[j].CompareTo(array[j - 1]) < 0)
{
T temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}
}
}
主程序如下:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Book[] bookArray = new Book[2];
Book book1 = new Book(100, "書一");
Book book2 = new Book(80, "書二");
bookArray[0] = book1;
bookArray[1] = book2;
Console.WriteLine("冒泡之前:");
foreach (Book b in bookArray)
{
Console.WriteLine("書名:{0},價格:{1}", b.Title, b.Price);
}
MethodSortHelper sorter = new MethodSortHelper();
sorter.BubbleSort(bookArray);
Console.WriteLine("冒泡之後:");
foreach (Book b in bookArray)
{
Console.WriteLine("書名:{0},價格:{1}", b.Title, b.Price);
}
Console.ReadKey();
}
}
//自定義實現IComparable接口
public class Book : IComparable
{
private int price;
private string title;
public Book() { }
public Book(int price, string title)
{
this.price = price;
this.title = title;
}
public int Price
{
get
{
return this.price;
}
}
public string Title
{
get
{
return this.title;
}
}
public int CompareTo(object obj)
{
Book book = (Book)obj;
return this.Price.CompareTo(book.Price);
}
}
}
輸出:
使用泛型方法的時候,除了這樣:
MethodSortHelper sorter = new MethodSortHelper();
sorter.BubbleSort(bookArray);
還可以這樣寫:
MethodSortHelper sorter = new MethodSortHelper();
sorter.BubbleSort(bookArray);
可見,泛型方法可以根據數據實例隱式推斷泛型是否滿足條件。
泛型的其他優點
避免隱式裝箱和拆箱
以下包含隱式裝箱和拆箱:
ArrayList list = new ArrayList();
for(int i = 0; i < 3; i++)
{
list.Add(i); //Add接收的參數類型是引用類型object,這裡包含了隱式裝箱
}
for(int i = 0; i < 3; i++)
{
int value = (int)list[i]; //引用類型強轉成值類型,拆箱
Console.WriteLine(value);
}
使用泛型避免隱式裝箱和拆箱:
List list = new List();
for(int i = 0; i < 3; i++)
{
list.Add(i);
}
for(int i = 0; i < 3; i++)
{
int value = list[i];
Console.WriteLine(value);
}
能在編譯期間及時發現錯誤
不使用泛型,在編譯期間不會報錯的一個例子:
List list = new List();
for(int i = 0; i < 3; i++)
{
list.Add(i);
}
for(int i = 0; i < 3; i++)
{
int value = list[i];
Console.WriteLine(value);
}
使用泛型,在編譯期間及時發現錯誤:
List list = new List();
int i = 100;
list.Add(i);
string value = (string)list[0];
使用泛型的技巧
在當前文件中給泛型起別名
using IntList = List;
IntList list = new IntList();
list.Add(1);
在不同文件中使用泛型別名,定義一個類派生於泛型
public class IntList : List{}