使用泛型的好處是「代碼重用」,極大的提升了開發效率,泛型爲開發者提供瞭如下優點:c++
1,源代碼保護 算法的源代碼不須要提供給使用泛型算法的開發人員,使用c++模板的泛型技術須要提供。(目前c++模板的泛型技術瞭解較少)算法
2,類型安全 給泛型算法指定類型時,編譯器能理解開發者意圖,只有兼容類型能經過,不兼容的時候編譯時候會報錯。安全
3,更清晰的代碼 因爲編譯器強制類型的安全性,減小源代碼中必須進行的轉型次數,使得代碼容易維護和編寫。例如:DateTime dt=dtList[0];從DateTime的集合中按照索引取出來的值能夠直接賦值給DateTime類型,不須要轉型。ide
4,更佳的性能 在操做值類型時候,非泛型集合會形成裝箱、拆箱操做,會形成託管堆上的內存分配,會形成頻繁的垃圾回收,影響性能。性能
補充:對於泛型方法,約束父類類型,與參數直接傳遞父類,在沒有返回值的狀況下是沒有區別的,假若有須要返回傳入的類型,則用泛型方法比較合適,由於經過泛型方法返回的類型不須要通過類型轉換 http://bbs.csdn.net/topics/380050195優化
1 public class AA{} 2 public class BB:AA{} 3 4 5 public void GetText<T>(T t) where T:AA 6 { 7 } 8 與 9 public void GetText(AA x) 10 {}之間是等效的,沒有區別。 11 12 13 public T GetText<T>(T t) where T:AA 14 { 15 } 16 public AA GetText(AA x) 17 在調用的地方是有區別的 18 19 BB b=new BB(); 20 var rtGetText=GetText<BB>(b); 21 var rtGetText2=(BB)GetText(B);//須要進行一次類型轉換
具備泛型類型參數的類型稱爲開放類型。ui
不能建立實例。例如Dictionary<,>,沒有指定參數,目前尚不清楚這個開放類型有什麼用。this
全部類型實參傳遞的都是實際數據類型爲封閉類型。spa
使用約束沒法將類型實參限制爲某一類型,能夠用一個靜態構造器來保證類型。以下.net
internal sealed class GenericTypeThatRequiresAnEnum<T>{ static GenericTypeThatRequiresAnEnum(){ if(!typeof(T).IsEnum){ throw new ArgumentException("T must be an enumerated type"); } } }
泛型類型仍然是類型,它能從其餘任何類型派生。
public class Node1<T> { public T m_data; public Node1<T> m_next; public Node1(T data) : this(data, null) { } public Node1(T data, Node1<T> next) { m_data = data; m_next = next; } public override string ToString() { // ABC return m_data.ToString()+((m_next!=null)?m_next.ToString():null); } }
上面例子必須是相同數據類型下使用,加入鏈表須要多個m_data爲多種類型的時候這種結構將沒法知足,這時候咱們能夠考慮抽出一個非泛型的基類,這樣繼承的泛型就能夠指定多種類型。這是一個泛型應用的技巧。
public class Node2 { protected Node2 m_next; public Node2(Node2 next) { m_next = next; } } public class TypeNode<T> : Node2 { public T m_data; public TypeNode(T data,Node2 next):base(next){ m_data = data; } public TypeNode(T data):this(data,null){ } public override string ToString() { // Tody is 時間。 return m_data.ToString() + ((m_next != null) ? m_next.ToString() : null); } }
這種性質不常常用,這裏簡單記一下只當瞭解。
簡化泛型的寫法多封裝一層去除"<"">"。
class DateTimeList:List<DateTime>{
//這裏不須要放入任何代碼。
}
這樣使用的時候就沒有<,>符號了。
DateTimeList dt=new DateTimeList();
這只是表面方便了,絕對不要單純出於加強代碼可讀性目的定義一個新類,事實上也不會這麼作,可是這樣寫會喪失同一性和相等性,以下代碼爲Flase
Boolean sameType=(typeof(List<DateTime>)==typeof(DateTimeList));
能夠經過使用using指令彌補相等性,添加以下結果爲True;
using DateTimeList=System.Collections.Generic.List<System.DateTime>;
使用泛型類型參數的一個方法在JIT(即時編譯)編譯時,Clr獲取方法的IL,用指定的實參進行替換,建立恰當的本地代碼,缺點是CLR要爲每種不一樣的方法、類型組合生成本地代碼,可能形成應用程序集顯著增大,損壞性能,稱之爲 代碼爆炸。
可是CRL內建了一些優化措施,緩解代碼爆炸。全部程序集使用List<DateTime>時候,只會生成一次,認爲全部引用類型實參都是徹底相同,List<String>和List<Stream>能夠公用,之因此會這樣,是由於全部引用類型的實參或者變量實際都是指向堆上的對象指針,而指針所有都是以相同的方式來操做。
泛型接口的一個例子是IComparable接口,在接口裏詳細寫
建議使用泛型的Action和Func委託,會在之後的委託中細說
不變量(invariant)表示泛型類型不可變。
逆變量(contravariant)表示泛型類型參數能夠從一個基類更改成該類的派生類,用in關鍵字標記,只出如今輸入位置。
協變量(covariant) 表示泛型類型能夠從一個派生類更改成它的基類型,用out關鍵字標記,只出如今輸出位置。
public delegate TResult Func<in T,out TResult>(T arg);
Func<object,ArgumentException> fn1=null;
func<string,Exception> fn2=fn1;//這裏不須要顯示轉換,由於逆變量,協變量
調用委託Exception e=fn2("");
使用要獲取泛型參數和返回值的委託時,建議儘可能使用in和out關鍵字,由於不會有不良反應。
泛型接口和泛型委託同樣也能夠用out和in。
用一個例子介紹下泛型的定義,下面一個類型定義了一個類型參數,一個方法定義了它本身的專用類型參數。
class GenericType<T>{ private T m_value; public GenericType(T value){m_value=value;} public TOutput Coverter(TOutput)(){ TOutput result=(TOutput)Convert.ChangeType(m_value,typeof(TOutput )); return result; } }
下面寫一個比較經典經常使用的泛型方法,2個參數互換
private static void Swap<T>(ref T o1,ref T o2){ T temp=o1; o1=o2; o2=temp; }
確保使用當前泛型是本身想要的類型。
例如以下方法,在類型沒有提供CompareTo方法時候會報錯。
private static T Min<T>(T o1,To2){
if(o1.CompareTo(o2)<0)
return o1;
return o2;
}
這個時候咱們就須要在該泛型方法添加泛型約束。
private static T Min<T>(T o1,To2) where T:IComparable<T>{
if(o1.CompareTo(o2)<0)
return o1;
return o2;
}
泛型約束主要分爲3種。
1,主要約束 主要約束能夠是一個引用類型,實參必須與約束相同或者派生,
例如where T:Stream ,使用該泛型方法必須是Stream 類型或者其派生類型。
where T:Class,使用該泛型方法必須是引用類型。
2,次要約束 次要約束表明的是一個藉口類型,指定的參數必須實現全部接口約束例如 where T:IComparable<T>
3,構造器約束 指定的實參必須實現公共無參構造器的一個非抽象類型where T:New()
下面是項目中用到的一個泛型方法,模板反序列化。使用了Newtonsoft.Json
public T GetTemplateData<T>() where T : TemplateData { if (!string.IsNullOrEmpty(TemplateDataJsonStr)) { T obj = (T)JsonConvert.DeserializeObject(TemplateDataJsonStr, typeof(T)); obj.CheckField(); return obj; } else return null; } public void SetTemplateData(TemplateData templateData) { TemplateDataJsonStr= JsonConvert.SerializeObject(templateData); }