看到他我一下子就悟了-- 泛型(2)
先說些題外話,只所以寫這些東西。是看了CSDN上的曹版主的一篇:手把手教程式設計,不知道有沒有人願意參與。說實話,我工作四年,總感覺暈暈乎乎的,好多技術都
懂,但是沒有一項是精通的。看了這篇帖子,說實在話我可想去,去聆聽大神的教導。主要是想提高自己,由於沒有時間,又因為身在北京。所以就沒有報名(呵呵,報名也
可能沒有機會去)。所以自己就去圖書館去搞他提出的這些概念。其實我更希望在北京的大神們也能組織類似的活動。我想響應一定也很多,其實我想如果能組織一次這樣的
活動,大神們也會得到提高的。這些都是我在圖書館看書的所得,分享給大家,同時也請管理員同志手下留情,不要每一篇都給打入冷宮,我已經很用心去做了。另外對這
感興趣的童鞋們可以加我的QQ348537081,我們可以討論一下心得。最後喜歡看書的童鞋也可以聯絡我,每週六首都圖書館,風雨無阻。
說的有些多,下面轉入正題。其實這篇文章是泛型介紹(接上一篇,具體的事例隨後呈上)的擴充套件與修改。
因為家中無法聯網,我都是提前用wps提前寫好的,所有格式上可能會有一些問題,所以請大家多擔待。
2.2介面約束(where T:interface-name)
為了規定某個資料型別必須實現某個介面,需要宣告一個介面約束(interface constraint).有了這種約束之後,甚至不需要執行型別轉換,就可以呼叫一個顯示的介面成員實現.接
口約束的主要功能與基類約束完全一樣。首先,它允許開發人員在泛型類中使用介面的成員。其次,它確保只能使用實現了特定介面的型別實參。這意味著對於任何給定的接
口約束,型別實參要麼是介面本身,要麼實現了介面的類。
注:可以通過使用逗號分隔的列表來同時指定多個介面。如果某個約束同時包含基類和介面,則先指定基類再指定介面列表。
如:為了確保T型別引數都是先了IComparable介面,
public class Binary<T> where T:System.IComparable{...}
編譯器會確保每次使用Binary類的時候,都必須指定一個實現了IComparable介面的型別引數.
下面的程式通過改寫前一個程式中的電話列表程式來說明介面約束的用途。在此程式中,PhoneNumber類被轉換為一個名為IPhoneNumber的介面。然後,Friend和Supplier實現了該介面。
class NotFoundException1 : Exception
{
public NotFoundException1() : base() { }
public NotFoundException1(string str) : base(str) { }
public NotFoundException1(string str, Exception inner) : base(str, inner) { }
protected NotFoundException1(System.Runtime.Serialization.SerializationInfo si,
System.Runtime.Serialization.StreamingContext sc)
: base(si, sc) { }
}
public interface IPhoneNumber
{
public string Number { get; set; }
public string Name { get; set; }
}
public class Friend1 : IPhoneNumber
{
public string Number { get; set; }
public string Name { get; set; }
public bool IsWorkNumber { get; set; }
public Friend1(string name, string num, bool wk)
{
Name = name;
Number = num;
IsWorkNumber = wk;
}
}
public class Supplier1 : IPhoneNumber
{
public string Name { get; set; }
public string Number { get; set; }
public Supplier1(string name, string num)
{
this.Name = name;
this.Number = num;
}
}
class FriendEmail1 { }
class PhoneList1<T> where T : IPhoneNumber
{
T[] phList;
int end;
public PhoneList1()
{
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)
{
foreach (T item in phList)
{
if (item.Name == name)
return item;
}
throw new NotFoundException1();
}
public T FindByNum(string num)
{
foreach (T item in phList)
{
if (item.Number == num)
return item;
}
throw new NotFoundException1();
}
2.3 struct/class 約束(where T:class/struct)
另一個重要的泛型約束是將型別引數限制為一個值型別或者一個引用型別.編譯器不允許在一個約束中將System.ValueType指定成基類.相反,C#提供了特殊的語法,這種語法同時適用於引用型別.在這種語法中,不是為T指定一個基類.相反,只需要指定關鍵字struct或者class.在同時存在其他約束時,class或者struct必須位於約束列表的開頭
例:
Public struct Nullable<T>:IFormattable,IComparable,IComparable<Nullable<T>>,INullable where T:struct
{//.......}
2.4 new()建構函式約束
New()建構函式約束允許開發人員例項化一個泛型型別的物件。一般情況下,無法建立一個泛型型別引數的例項。然而,new()約束改變了這種情況,它要求型別實參必須
提供一個無引數的建構函式。在使用new()約束的時候,可以通過呼叫該無參建構函式來建立物件。
class myclass
{
public myclass() { }
}
class Test<T> where T : new()
{
T obj;
public Test()
{
obj = new T();
}
}
呼叫:
Test<myclass> x = new Test<myclass>();
注意:myclass 不必顯示地宣告一個無引數建構函式,預設的建構函式也可以滿足這種約束。然而,如果某個類除了無參的建構函式外還需要定義其他的建構函式,那麼必須
為該類顯式地宣告不含引數的建構函式。
使用new()時,應注意三點:
一、它可以和其他約束一起使用,但必須位於約束列表的末端。
二、New()不允許給型別引數的建構函式傳遞實參
三、不可以同時使用new()約束和值型別約束
2.5多重約束
同一個引數可以使用多個約束。這種情況下,需要使用一個逗號分隔的約束列表.在該列表中,第一個約束必須是class或者struct(如果存在的話),或者基類(如果被指
定)。指定class或者struct的同時也指定基類約束是非法的。接下來是介面約束。最後是new ()約束。如:
Class Gen<T> where T:myClass,IMyInterface,new(){}
如果有多個型別引數,那麼每個型別名稱的前面都要使用一個where關鍵字.如:
Class Gen<T,V> where T:class
Where T:struct
{//.....}
2.6.泛型方法
為了定義泛型方法,需要緊接在方法名之後新增型別引數語法,如
public T method<T>(T params)
{
return params;
}
泛型方法也允許指定約束:
public T method<T>(T params)
where T:IComparable
{
return params;
}
2.7.Default關鍵字:
要確定用於建立泛型類例項的型別,需要了解一個最基本的情況:他們是引用型別還是值型別.若不知道這個情況,就不能用下面的程式碼賦予null值:
public class myGenericClass<T1,T2,T3>
{
T1 t1;
public myGenericClass()
{
t1=null;
}
}
如果T1是值型別,則t1不能是null,所以這段程式碼將不會編譯.幸好,我們可以用default關鍵字的新用法解決了它.
public myGenericClass()
{
t1=default(T1);
}
其結果是:如果t1是引用型別,就給它賦予null,如果它是值型別,就賦予預設值.如數字型別,這個預設值就是0.
幾個泛型型別的示例:
2.8定義泛型結構
public struct myStruct<T1,T2>
{
public T1 item1;
public T2 item2;
}
2.9定義泛型介面 interface myInterfacee<T>{}
2.10 .定義泛型方法
public T GetDefault<T>()
{
return default(T);
}
2.11定義泛型委託
public delegate T1 myDelegate<T1,T2>(T2 op1,T2 op2) where T1:T2
結束語:泛型到這了,下一次介紹下反射,關於前幾篇C#我會抽時間重新寫的,能讓他更詳細點,其實這次C#基礎知識的複習讓我學到很多東西,以前模糊的概念,
現在變得非常清晰了。我曾經面試過好多人,有工作三年,有兩年,甚至工作經驗比我還長的。對這些基礎性的知識都知之甚少,當然也包括我自己。因為如果沒
有這些概念,工作中也不會可慮到這些東西,當然也就談不上引用。所以我們都只能做底層程式。程式猿想提高,重新學這些基礎知識吧,真的……