1.泛型概念:
本質上,術語”泛型”指的是”參數化型別(parameterized types)”.參數化型別非常重要,因為它們可以在建立類.結構.方法和委託的時候將要操作的資料類型作為參
數進行指定.使用參數化型別的類.結構.方法和委託都可以稱為泛型,如”泛型類”或者”泛型方法”.
在具體聲明一個變數或者執行個體化之前,型別參數T只是一個預留位置。等到具體聲明和執行個體化的時候,編譯器要求代碼指定型別參數。泛型型別聲明了泛型參數預留位置類型,由泛型型別的使用者填寫這些預留位置,並作為泛型的參數提供給泛型型別.
2.泛型約束:約束聲明了泛型要求的型別參數的特徵。
為了聲明一個約束,需要使用where關鍵字,後跟一對”參數:要求”.其中,”參數”必須是泛型型別中定義的一個參數,而”要求”用於限制類型從
中”派生”的類或介面,或者限制必須存在一個預設構造器,或者限制使用一個引用/實值型別約束.
2.1基類約束(where T:base-class-name)
有的時候,你可能需要限制類型從一個特定的類派生.這是用基類約束(base class constraint)做到的.使用基類約束,可以指定某個類型實參
必須繼承的基類.基類約束有兩個重要功能.
首先,他允許在泛型類中使用由約束指定的基類所定義的成員.例如,可以調用基類的方法或者使用基類的屬性.如果沒有基類約束,編譯器就無法知道某
個類型實參擁有哪些成員.通過提供基類約束,編譯器將知道所有的類型實參都擁有由指定的基類所定義的成員.
基類約束的第二個功能是,確保只適用支援指定基類的類型實參.這意味著對於任意給定的基類約束,類型實參要麼是基類本身,要麼是派生於該基
類.如果試圖使用沒有匹配或者繼承指定的類型實參,就會導致編譯錯誤例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//泛型:基類約束
//基類約束兩個作用:1.基類約束允許泛型類訪問基類的成員
// 2.確保只能使用滿足該約束的型別參數,從而實作類別型安全
namespace generic
{
/*案例描述:假設要建立一個管理電話號碼列表的工具.另外,假定不同組的使用者
使用的是不同的列表.例如,一個列表用於朋友,令外一個列表用於供應商等.
*/
/// <summary>
/// PhoneNumber基類,它用於儲存姓名和姓名相對應的電話號碼
/// </summary>
class PhoneNumber
{
public string Number { get; set; }
public string Name { get; set; }
public PhoneNumber(string n, string num)
{
this.Name = n;
this.Number = num;
}
}
/// <summary>
/// 朋友電話
/// </summary>
class Friend : PhoneNumber
{
/// <summary>
/// 電話號碼是否為工作號碼
/// </summary>
public bool IsWorkNumber { get; private set; }
public Friend(string n, string num, bool wk)
: base(n, num)
{
this.IsWorkNumber = wk;
}
}
/// <summary>
/// 供應商電話
/// </summary>
class Supplier : PhoneNumber
{
public Supplier(string n, string num)
: base(n, num)
{
}
}
/*為了管理電話列表,下面建立一個名為PhoneList的類.由於希望該類能夠
* 管理任意類型的電話列表,因此將其實現為泛型.另外,由於列表管理的一部分內容是
* 根據姓名查詢號碼,或者根據號碼查詢姓名,因此要給它添加約束,從而
* 確儲存儲在列表中的對象的類型必須是PhoneNumber衍生類別的執行個體
*/
/// <summary>
/// 管理任意類型的電話列表
/// </summary>
/// <typeparam name="T"></typeparam>
class PhoneList<T> where T:PhoneNumber
{
T[] phList;
int end;
public PhoneList()
{
phList = new T[10];
end = 0;
}
public bool Add(T newEntry)
{
if (end == 10) return false;
phList[end] = newEntry;
end++;
return true;
}
public T FindByName(string name)
{
for (int i = 0; i < end; i++)
{
if (phList[i].Name == name)
return phList[i];
}
throw new NotFoundException();
}
public T FindByNumber(string number)
{
for (int i = 0; i < end; i++)
{
if (phList[i].Number == number)
return phList[i];
}
throw new NotFoundException();
}
}
/// <summary>
/// 此類沒有繼承PhoneNumber,因此不能用於建立PhoneList
/// </summary>
class EmailFriend
{
//.....
}
/*
* 這是一個定製異常,雖然該樣本只使用預設建構函式,但是出於說明的
* 目的,NotFoundException實現了Exception定義的所有建構函式
* 注意:這些建構函式只調用了Exception定義的相等基類建構函式.
* NotFoundException沒有向Exception添加任何內容,因此不需要
* 執行任何進一步的操作
*/
class NotFoundException : Exception
{
public NotFoundException():base(){}
public NotFoundException(string str):base( str){}
public NotFoundException(string str, Exception inner) :
base(str, inner) { }
protected NotFoundException(
System.Runtime.Serialization.SerializationInfo si,
System.Runtime.Serialization.StreamingContext se) :
base(si, se) { }
}
}
怎樣調用:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Collections;namespace generic{ class Program { static void Main(string[] args) { BaseClassConstraint(); Console.Read(); } //基類約束 public static void BaseClassConstraint() { //可以通過編譯 PhoneList<Friend> plist = new PhoneList<Friend>(); //錯誤添加 //plist.Add(new Friend() {Name="Tom",Number="555-1234",IsWorkNumber=true }); //正確添加 plist.Add(new Friend("Tom", "5555-333", true)); plist.Add(new Friend("Gary", "5555-332", true)); plist.Add(new Friend("WangC", "5555-331", false)); try { Friend frnd = plist.FindByName("Gary"); Console.WriteLine(frnd.Name+":"+frnd.Number); if(frnd.IsWorkNumber) Console.WriteLine("(work)"); else Console.WriteLine(); } catch (NotFoundException) { Console.WriteLine("Not Found"); } //供應商 PhoneList<Supplier> plist2 = new PhoneList<Supplier>(); plist2.Add(new Supplier("Global Hardware", "400-123")); plist2.Add(new Supplier("Computer", "400-124")); plist2.Add(new Supplier("NetWorkCity", "400-125")); try { Supplier sp = plist2.FindByNumber("400-124"); Console.WriteLine(sp.Name+":"+sp.Number); } catch (NotFoundException) { Console.WriteLine("Not Found"); } //沒有繼承的 // PhoneList<EmailFriend> plist3 = new PhoneList<EmailFriend>(); } } }
未完待續……