建議32:總是優先考慮泛型
泛型的優點是多方面的,無論泛型類還是泛型方法都同時具備可重用性、類型安全性和高效率等特性,這是非泛型和非泛型方法無法具備的。
以可重用性為例:
class MyList { private int[] items; public int this[int i] { get { return items[i]; } set { this.items[i] = value; } } public int Count { get { return items.Length; } } ///省略其他方法 }
該類型只支持整型,如果要讓類型支持字符串,有一種方法是重新設計一個類。但是這兩個類型的屬性和方法都是非常接近的,如果有一種方法可用讓類型接收一個通用的數據類型,這樣代碼就可以復用了,同時類型也只要一個就夠了。泛型完成的就是這樣一個功能。泛型實現如下:
class MyList<T> { private T[] items; public T this[int i] { get { return items[i]; } set { this.items[i] = value; } } public int Count { get { return items.Length; } } ///省略其他方法 }
可以把T理解為一個占位符,在C#泛型編譯生成的IL代碼中,T就是一個占位符的角色。在運行時,即時編譯器(JIT)會用實際代碼中輸入的T類型來代替T,也就是說,在由JIT生成的本地代碼中,已經使用了實際的數據類型。我們可以吧MyList<T>和MyList<T>視作兩個不同類型,但是,這僅是對本地代碼而言,對應實際的C#代碼,它僅僅擁有一個類型,那就是泛型類型MyList<T>。
如果不用泛型來實現,另一種方法是讓MyList的編碼從object的角度去設計。在C#的世界中,所有類型(包括值類型和引用類型)都是繼承自object,如果讓MyList足夠通用,就需要讓MyList針對object編碼,代碼如下:
class MyList { private object[] items; public object this[int i] { get { return items[i]; } set { this.items[i] = value; } } public int Count { get { return items.Length; } } ///省略其他方法 }
這會讓下面的代碼編譯通過:
list[0]=123;
list[1]="123";
由上面兩行代碼帶來的問題就是非類型安全性。讓類型支持類型安全,可以讓程序在編譯期間就過濾掉部分Bug,同時,也能讓代碼避免“轉型為object類型”或“從object轉型為實際類型”所帶來的性能損耗。尤其是當操作類型是值類型時,還會帶來裝箱拆箱的性能損耗。
泛型為C#語言帶來了革命性的變化,FCL之後的很多功能都是借助泛型才得到很好的實現,如LINQ。LINQ借助於泛型和擴展方法,有效地豐富了集合的查詢功能,同時避免了代碼爆炸並提升了操作性能。我們在設計自己的類型時,應充分考慮到泛型的優點,讓自己的類型成為泛型類。
轉自:《編寫高質量代碼改善C#程序的157個建議》陸敏技