C#泛型


為什么會出現泛型

在泛型還沒有出來之前,使用那些為不同類型設計的方法(比如ArrayList)和只有傳參不同,其他邏輯都相同的方法時,都會想到所有類型的基類object,看似完美的解決了問題。

但是還是有大問題會出現:

1.會因為沒有記住使用的類型而出錯,造成類型不兼容;

2.類型強制轉換出錯;

3.值類型和引用類型的互化即裝箱拆箱使系統性能下降。

        public void Do()
        {
            GetArrayList(1);
            GetArrayList("123");
            GetArrayList(true);
            B b = new B();
            GetArrayList(b);
        }
        public void GetArrayList(object obj)
        {
            
        }

泛型的出現很好的解決這個問題。

泛型怎么使用

泛型有兩種形式:泛型類型(包括類、接口、委托和結構——沒有泛型枚舉)和泛型方法。兩者都是表示API的基本方法(不管是指單獨的泛型方法還是完整的泛型類型),在平時期望出現一個普通類型的地方,用一個類型參數。類型參數是真實類型的占位符。在泛型聲明中,類型參數要放在一對尖括號內,並以逗號分隔。
舉個例子C#自帶的集合類Dictionary<TKey,TValue>,實例化的時候一般都是下面這樣,在Dictionary <TKey,TValue>中,類型參數是TKey和TValue。使用泛型類型或方法時,要用真實的類型代替。string替代TKey,int替代TValue
Dictionary<string, int> dic1 = new Dictionary<string, int>();
dic1.Add("a", 1);
dic1.Add("b", 2);
Dictionary<int, bool> dic2 = new Dictionary<int, bool>();
dic2.Add(1, true);
dic2.Add(2, false);

感興趣的話可以,F12看一下Dictionary<TKey,TValue>如何聲明泛型類型,實現泛型接口,聲明無參構造函數。

這里有個小常識:在向其他人描述泛型類型時,通常使用of來介紹類型參數或實參,因此List<T>讀作list of T。

類型的命名規范:雖然可以使用帶有T、U和V這樣的類型參數的類型,但從中根本看不出實際指的是什么,也看不出它們應該如何使用。相比之下,像Dictionary<TKey,TValue>這樣的命名就要好得多,TKey明顯代表鍵的類型,而TValue代表值的類型。如果只有一個類型參數,而且它的含義很清楚,那么一般使用T(List<T>就是一個很好的例子)
 
類型約束
到目前為止說的泛型可以指定任意類型,他們未做約束。但是我們在工作中經常想指定規則值接受引用類型或者值類型,從而接受有效類型的實參。
1. 引用類型約束
確保使用的類型實參是引用類型,類型實參任何類、接口、數組、委托等
public class ReturnResult<T> where T : class
{
     List<T> ts = new List<T>();
}

2.值類型約束

確保使用的類型參數是值類型。

public class ReturnResult<T> where T : struct
{
      .......  
}

使用的話就是 ReturnResult<int> result = new ReturnResult<int>();在平時的使用中用的比較少

3.構造函數類型約束

確保類型實參有一個無參的構造函數,必須是所有類型參數最后一個約束

    /// <summary>
    /// 有無參構造函數的泛型約束
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ReturnResult<T> where T : new()
    {
        
    }
    public class Person
    {
        public string Id { get; set; }
        public string Name { get; set; }
        //增加無參的構造函數
        public Person()
        {
        }
    }
    public class Test
    {
        public void GetTest()
        {
            //實例化
            ReturnResult<Person> result = new ReturnResult<Person>();
        }
    }

4.轉換類型約束

確保一個類型的實參必須轉化為另一種類型的實參,摘自《深入理解C#》一書的一個圖片

 

 5.組合約束

應用中可能存在多個約束的可能性,當我們把不通類型的約束組合在一起時,就要考慮他們之間的共存問題了。顯然沒有一個類型即是引用類型有是值類型,這種組合就是錯誤的;如果存在多個約束組合,類應該出現在接口的前面,不能多次指向同一個接口,new()放在最后,不同的類型可以有不同的約束,分別由單獨的where引入,來看一些例子

    //有效的
    class D<T> where T : class, IDisposable, new() { }
    class E<T> where T : struct, IDisposable { }
    class F<T, U> where T : class where U : struct { }
    class G<T, U> where T : Stream where U : IDisposable { }
    //無效的
    class H<T> where T : class, struct { }
    class I<T> where T : class, Stream { }
    class J<T> where T : new(), class { }
    class M<T, U> where T : struct where U : class,T { }

協變和逆變

下節說

附錄:C#自帶的一些泛型

 

 

 


免責聲明!

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



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