看到他我一下子就悟了-- 泛型(1)
阿新 • • 發佈:2022-05-02
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>();
}
}
}
未完待續……