1、什麼是泛型git
源碼算法
1.泛型類和泛型方法兼複用性、類型安全和高效率於一身,是與之對應的非泛型的類和方法所不及。泛型普遍用於容器(collections)和對容器操做的方法中。.NET框架2.0的類庫提供一個新的命名空間System.Collections.Generic,其中包含了一些新的基於泛型的容器類。要查找新的泛型容器類(collection classes)的示例代碼,請參見基礎類庫中的泛型。固然,你也能夠建立本身的泛型類和方法,以提供你本身的泛化的方案和設計模式,這是類型安全且高效的。設計模式
2、泛性優勢緩存
1.在咱們.net 1.0剛剛推出的時候,咱們有不一樣的類型調用同一個方法的時候,要麼給每個類型寫一個專門的方法,還有一種處理方案就是,利用了咱們繼承的特色,由於Object是全部類型的基類,咱們就能夠定義一個Object參數的方法,可是這樣會有一個缺點,咱們都知道Object是引用類型,當咱們實際的參數是值類型的時候須要拆箱、裝箱操做這裏就是不必的消耗了。安全
/// <summary> /// 咱們能夠作一個測試,將三種方法進行一億次操做對比時間消耗 /// </summary> public void Show() { Console.WriteLine("****************Monitor******************"); { //咱們先建立幾個計數的變量 int iValue = 12345; long commonSecond = 0; long objectSecond = 0; long genericSecond = 0; //這個是普通類型的方法 { Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < 100000000; i++) { ShowInt(iValue); } watch.Stop(); commonSecond = watch.ElapsedMilliseconds; } //這個是Object類型的方法 { Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < 100000000; i++) { ShowObject(iValue); } watch.Stop(); objectSecond = watch.ElapsedMilliseconds; } //這個是泛型類型的方法 { Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < 100000000; i++) { ShowT<int>(iValue); } watch.Stop(); genericSecond = watch.ElapsedMilliseconds; } Console.WriteLine("commonSecond={0},objectSecond={1},genericSecond={2}" , commonSecond, objectSecond, genericSecond); } } #region 實例一 /// <summary> /// 打印個int值 /// </summary> /// <param name="iParameter"></param> public static void ShowInt(int iParameter) { //Console.WriteLine(iParameter); } /// <summary> /// 打印個string值 /// </summary> /// <param name="sParameter"></param> public static void ShowString(string sParameter) { //Console.WriteLine(sParameter); } /// <summary> /// 打印個DateTime值 /// </summary> /// <param name="oParameter"></param> public static void ShowDateTime(DateTime dtParameter) { //Console.WriteLine(dtParameter); } /// <summary> /// 當咱們的方法須要給多個類型調用的時候,在沒有泛型以前咱們 /// 就只能使用object 基類來作這樣的事情,可是肯定就是object是引用 /// 類型或形成不必的拆箱裝箱操做 /// </summary> /// <param name="oParameter"></param> public static void ShowObject(object oParameter) { //Console.WriteLine(oParameter); } /// <summary> /// .Net 2.0出現來,咱們可使用T做爲一個展位的類型, /// T只有會在編譯的時候纔會獲取咱們的類型,達到一種延遲 /// 效果。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="num"></param> public void ShowT<T>(T oParameter) { //Console.WriteLine(oParameter); } #endregion
2.上面我針對幾種方法測試的時候,能夠明顯發現使用Object方法慢於普通方法,和泛型方法,咱們有能夠看到泛型方法會比普通方法快那麼一點點,不過能夠忽略不計。由於泛型方法的類型不會當即編譯出來,會生成一個佔位符的東西。框架
3.咱們定義一個泛型,它不會當即獲取咱們的類型,會生成一個佔位符,只有咱們在運行中的時候才獲取類型。一切延遲的思想。ide
//咱們能夠打印出來,能夠看到會生成一個展位符 Console.WriteLine(typeof(List<>)); Console.WriteLine(typeof(Dictionary<,>));
3、泛型約束函數
1.雖然咱們的泛型能夠放置任何類型,可是若是咱們想要限制咱們的方法不能胡亂使用,就可使用咱們的泛型約束性能
約束
|
描述
|
where T: struct
|
類型參數必須爲值類型。
|
where T : class
|
類型參數必須爲類型。
|
where T : new()
|
類型參數必須有一個公有、無參的構造函數。當於其它約束聯合使用時,new()約束必須放在最後。
|
where T : <base class name>
|
類型參數必須是指定的基類型或是派生自指定的基類型。
|
where T : <interface name>
|
類型參數必須是指定的接口或是指定接口的實現。能夠指定多個接口約束。接口約束也能夠是泛型的。
|
/// <summary> /// 在方法或者類上面咱們能夠約束T 的類型 /// 在方法後面咱們可使用Where 約束 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> public void Show<T>() where T : BaseEntity, IBaseEntity, new() { //僅當T是引用類型時,t = null語句纔是合法的; t = 0只對數值的有效 T tNew = default(T); T tNew1 = new T(); Console.WriteLine(tNew); Console.WriteLine(tNew1); Console.WriteLine(typeof(T)); } public static T Get<T>(T t) //where T : ISports//接口約束 //where T : class//引用類型約束 //where T : struct//值類型約束 //where T : BaseEntity //約束基類 where T : new()//無參數構造函數約束 { //T tNew = null; //T tNew = default(T);//會根據T的不一樣 賦予默認值 T tNew = new T(); return t; }
4、泛型進階測試
1.協變、逆變(不過我在項目中尚未遇到過這樣的需求,可是思想仍是能夠的)
/// <summary> /// 協變 ,逆變 /// </summary> public class CCTest { public void Show() { //在咱們正常的編碼 is a 子類實例化能夠等於父類 Bird bird = new Bird(); Bird sparrow = new Sparrow(); //可是咱們的泛型就不能夠,就有點不科學了 //List<Bird> birds = new List<Sparrow>(); //雖然這樣是能夠,可是實際上是最後面咱們遍歷了List<Sparrow>()轉化爲了Bird List<Bird> birds = new List<Sparrow>().Select(x => (Bird)x).ToList(); //咱們微軟也出了對應的方法,就是咱們的協變、逆變 //協變:只能將泛型類型當成返回值 out T //逆變:只能將泛型類型當場參數 in T //協變 IEnumerable<Bird> birdsOut = new List<Bird>(); IEnumerable<Bird> birdsOut1 = new List<Sparrow>(); ICustomerListOut<Bird> customerListOut = new CustomerListOut<Bird>(); ICustomerListOut<Bird> customerListOut1 = new CustomerListOut<Sparrow>(); //逆變 ICustomerListIn<Sparrow> customerListIn = new CustomerListIn<Sparrow>(); ICustomerListIn<Sparrow> customerListIn1 = new CustomerListIn<Bird>(); //協變、逆變 IMyList<Sparrow, Bird> myList1 = new MyList<Sparrow, Bird>(); IMyList<Sparrow, Bird> myList2 = new MyList<Sparrow, Sparrow>();//協變 IMyList<Sparrow, Bird> myList3 = new MyList<Bird, Bird>();//逆變 IMyList<Sparrow, Bird> myList4 = new MyList<Bird, Sparrow>();//逆變+協變 } } #region 類型 /// <summary> /// 鳥類 /// </summary> public class Bird { public int Id { get; set; } } /// <summary> /// 麻雀繼承鳥類 /// </summary> public class Sparrow : Bird { public string Name { get; set; } } #endregion #region 接口和類 #region 協變 public interface ICustomerListOut<out T> { //若是咱們將T 改爲參數,立刻報錯 T Get(); } public class CustomerListOut<T> : ICustomerListOut<T> { public T Get() { throw new NotImplementedException(); } } #endregion #region 逆變 public interface ICustomerListIn<in T> { //若是咱們將T 改爲返回值,立刻報錯 void Get(T t); } public class CustomerListIn<T> : ICustomerListIn<T> { public void Get(T t) { throw new NotImplementedException(); } } #endregion #region 協變,逆變 public interface IMyList<in inT, out outT> { void Show(inT t); outT Get(); outT Do(inT t); } public class MyList<T1, T2> : IMyList<T1, T2> { public void Show(T1 t) { Console.WriteLine(t.GetType().Name); } public T2 Get() { Console.WriteLine(typeof(T2).Name); return default(T2); } public T2 Do(T1 t) { Console.WriteLine(t.GetType().Name); Console.WriteLine(typeof(T2).Name); return default(T2); } } #endregion #endregion
2.泛型緩存,當咱們執行一個類以前都會先執行咱們的靜態構造函數,和初始化咱們的靜態字段。而後將執行的信息保存到內存中,直到咱們的程序重啓以後,纔會失效。主要是利用了咱們靜態容器一旦執行完以後會一直保存在程序內存中,而後配合咱們的泛型類,就能夠根據不一樣的泛型產生不一樣的靜態容器,分別存儲了不一樣信息(我在項目中常常會使用這個技術比較方便,性能也很奈斯。)
public class GenericCacheTest { public static void Show() { for (int i = 0; i < 5; i++) { Console.WriteLine(GenericCache<int>.GetCache()); Thread.Sleep(10); Console.WriteLine(GenericCache<long>.GetCache()); Thread.Sleep(10); Console.WriteLine(GenericCache<DateTime>.GetCache()); Thread.Sleep(10); Console.WriteLine(GenericCache<string>.GetCache()); Thread.Sleep(10); Console.WriteLine(GenericCache<GenericCacheTest>.GetCache()); Thread.Sleep(10); } } } /// <summary> /// 字典緩存:靜態屬性常駐內存 /// 可是字典緩存每次都須要運行尋址算法,去算地址 /// </summary> public class DictionaryCache { private static Dictionary<Type, string> _TypeTimeDictionary = null; static DictionaryCache() { Console.WriteLine("This is DictionaryCache 靜態構造函數"); _TypeTimeDictionary = new Dictionary<Type, string>(); } public static string GetCache<T>() { Type type = typeof(Type); if (!_TypeTimeDictionary.ContainsKey(type)) { _TypeTimeDictionary[type] = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff")); } return _TypeTimeDictionary[type]; } } /// <summary> /// 每一個不一樣的T,都會生成一份不一樣的副本 /// 適合不一樣類型,須要緩存一份數據的場景,效率高 /// 不能主動釋放 /// /// 相比上面字典緩存,這種緩存相比要好不少,由於不須要查找地址 /// </summary> /// <typeparam name="T"></typeparam> public class GenericCache<T> { static GenericCache() { Console.WriteLine("This is GenericCache 靜態構造函數"); _TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff")); } private static string _TypeTime = ""; public static string GetCache() { return _TypeTime; } }