看到他我一下子就悟了-- 泛型(2)


   先說些題外話,只所以寫這些東西。是看了CSDN上的曹版主的一篇:手把手教編程,不知道有沒有人願意參與。說實話,我工作四年,總感覺暈暈乎乎的,好多技術都

懂,但是沒有一項是精通的。看了這篇帖子,說實在話我可想去,去聆聽大神的教導。主要是想提高自己,由於沒有時間,又因為身在北京。所以就沒有報名(呵呵,報名也

可能沒有機會去)。所以自己就去圖書館去搞他提出的這些概念。其實我更希望在北京的大神們也能組織類似的活動。我想響應一定也很多,其實我想如果能組織一次這樣的

活動,大神們也會得到提高的。這些都是我在圖書館看書的所得,分享給大家,同時也請管理員同志手下留情,不要每一篇都給打入冷宮,我已經很用心去做了。另外對這

感興趣的童鞋們可以加我的QQ348537081,我們可以討論一下心得。最后喜歡看書的童鞋也可以聯系我,每周六首都圖書館,風雨無阻。

  說的有些多,下面轉入正題。其實這篇文章是泛型介紹(接上一篇,具體的事例隨后呈上)的擴展與修改。

因為家中無法聯網,我都是提前用wps提前寫好的,所有格式上可能會有一些問題,所以請大家多擔待。

2.2接口約束(where Tinterface-name

  為了規定某個數據類型必須實現某個接口,需要聲明一個接口約束(interface constraint).有了這種約束之后,甚至不需要執行類型轉換,就可以調用一個顯示的接口成員實現.

口約束的主要功能與基類約束完全一樣。首先,它允許開發人員在泛型類中使用接口的成員。其次,它確保只能使用實現了特定接口的類型實參。這意味着對於任何給定的接

口約束,類型實參要么是接口本身,要么實現了接口的類。

注:可以通過使用逗號分隔的列表來同時指定多個接口。如果某個約束同時包含基類和接口,則先指定基類再指定接口列表。


如:為了確保T類型參數都是先了IComparable接口,


public class Binary<T> where T:System.IComparable{...}


編譯器會確保每次使用Binary類的時候,都必須指定一個實現了IComparable接口的類型參數.

 

  下面的程序通過改寫前一個程序中的電話列表程序來說明接口約束的用途。在此程序中,PhoneNumber類被轉換為一個名為IPhoneNumber的接口。然后,FriendSupplier實現了該接口。

  

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 TIComparable
{
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#基礎知識的復習讓我學到很多東西,以前模糊的概念,

現在變得非常清晰了。我曾經面試過好多人,有工作三年,有兩年,甚至工作經驗比我還長的。對這些基礎性的知識都知之甚少,當然也包括我自己。因為如果沒

有這些概念,工作中也不會可慮到這些東西,當然也就談不上引用。所以我們都只能做底層程序。程序猿想提高,重新學這些基礎知識吧,真的……

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM