【1】:泛型介紹
泛型是C#2.0中一個重要的新特性,泛型是CLR和編程語言提供的一種特殊機制,它支持另一種形式的代碼重用。泛型通常用與集合以及作用於集合的方法一起使用,當然也可以單獨使用.
一般情況下,創建泛型類的過程為:從一個現有的具體類開始,逐一將每個類型更改為類型參數,直至達到通用化和可用性的最佳平衡。 創建您自己的泛型類時,需要特別注意以下事項:
-
將哪些類型通用化為類型參數。
通常,能夠參數化的類型越多,代碼就會變得越靈活,重用性就越好。 但是,太多的通用化會使其他開發人員難以閱讀或理解代碼。
-
如果存在約束,應對類型參數應用什么約束
一條有用的規則是,應用盡可能最多的約束,但仍使您能夠處理必須處理的類型。 例如,如果您知道您的泛型類僅用於引用類型,則應用類約束。 這可以防止您的類被意外地用於值類型,並允許您對 T 使用 as 運算符以及檢查空值。
-
是否將泛型行為分解為基類和子類。
由於泛型類可以作為基類使用,此處適用的設計注意事項與非泛型類相同。 請參見本主題后面有關從泛型基類繼承的規則。
-
是否實現一個或多個泛型接口。
例如,如果您設計一個類,該類將用於創建基於泛型的集合中的項,則可能必須實現一個接口,如 IComparable,其中 T 是您的類的類型。
【2】:泛型的表示方式
System.Collections.Generic 命名空間包含定義泛型集合的接口和類,泛型集合允許用戶創建強類型集合,它能提供比非泛型強類型集合更好的類型安全性和性能。創建泛型類的過程為:從一個現有的具體類開始,逐一將每個類型更改為類型參數,直至達到通用化和可用性的最佳平衡
【3】:泛型的好處
1 public List<TrainingUser>GetTrainingUser(string userId) 2 { 3 DataTable dt = 4 SqliteHelper.ExecuteDataset(System.Data.CommandType.Text, 5 @" 6 SELECT DISTINCT UserId,TrainingId FROM TRAININGUSER AS TU 7 INNER JOIN [USER] AS U 8 ON U.ID = TU.USERID 9 JOIN [TRAINING] AS T 10 ON T.ID = TU.TRAININGID 11 WHERE U.ID = '"+userId+"' AND T.ENDTIME > DATETIME('now', 'localtime') AND T.StartTime <= DATETIME('now', 'localtime') ;").Tables[0]; 12 return DataTableToList(dt); 13 } 14 15 private List<TrainingUser> DataTableToList(DataTabledt) 16 { 17 List<TrainingUser> list = new List<TrainingUser>(); 18 if(dt. Rows.Count > 0 ) 19 { 20 foreach (DataRow row in dt .Rows) 21 { 22 TrainingUser trainingUser = new TrainingUser(); 23 if(row["UserId" ] != null) 24 { 25 trainingUser .UserId = row["UserId"].ToString(); 26 } 27 if(row["TrainingId" ] != null) 28 { 29 trainingUser.TrainingId = row["TrainingId"].ToString(); 30 } 31 list.Add(trainingUser); 32 } 33 } 34 return list; 35 }
1 public static List<T> ToList1<T>(DataTable dt) whereT : class, new() 2 { 3 var prlist =new List<PropertyInfo>(); 4 Type type = typeof(T); 5 Array.ForEach( 6 type.GetProperties(), 7 p => 8 { 9 if(dt.Columns.IndexOf(p.Name) !=-1) 10 { 11 prlist.Add(p); 12 } 13 }); 14 var oblist = new List<T>(); 15 16 // System.Data.SqlTypes. 17 foreach(DataRow row in dt.Rows) 18 { 19 var ob = new T(); 20 prlist.ForEach( 21 p => 22 { 23 if(row[p.Name] != DBNull.Value) 24 { 25 p.SetValue(ob, row[p.Name], null); 26 } 27 }); 28 oblist.Add(ob); 29 } 30 31 return oblist; 32 }
在上面的這個方法中,我們定義了一個泛型方法,內部實現中是使用了反射的原理,將DataTable轉換為了List(反射后續隨筆中總結,此處只關注泛型部分即可),我們定義了一個靜態的返回值為List<T> ,前面我們說過 T : 代表任意類型(枚舉除外),ToList1<T>,說明我們在調用這個方法的時候,同時要賦予方法名一個類型值,這個類型要和它的返回值類型一致(泛型是類型安全的),Where : 用於限制T的條件 ,例如 where T : class,new() 表示 T 只能是一個類,或者一個類型對象,那么我們在調用的時候就可以這樣來
1 public List<TrainingUser>GetTrainingIdByUserId(string userId) 2 { 3 List<TrainingUser> trainingUserList = DataTableHelper.ToList1<TrainingUser>( 4 SqliteHelper.ExecuteDataset(System.Data.CommandType.Text, 5 @" 6 SELECT DISTINCT UserId,TrainingId FROM TRAININGUSER AS TU 7 INNER JOIN [USER] AS U 8 ON U.ID = TU.USERID 9 JOIN [TRAINING] AS T 10 ON T.ID = TU.TRAININGID 11 WHERE U.ID = '"+ userId +"' AND T.ENDTIME > DATETIME('now', 'localtime') AND T.StartTime <= DATETIME('now', 'localtime') ;").Tables[0]); 12 return trainingUserList ; 13 }
1 private static void ListTest() 2 { 3 List<int>list = new List<int>(); 4 for(inti = 0; i < 100; i++) 5 { 6 list.Add(i); 7 int a = list[i]; 8 } 9 list =null; 10 } 11 private static void ArrListTest() 12 { 13 ArrayList arr = new ArrayList(); 14 for(inti = 0; i <100; i++) 15 { 16 arr.Add(i); 17 int s = (int)arr[i]; 18 } 19 arr = null; 20 } 21 22 Stopwatch sw = new Stopwatch(); 23 sw.Start(); 24 ListTest(); 25 Console.WriteLine(" 使用泛型List執行值類型方法歷時 : "+ sw.Elapsed.ToString()); 26 sw.Stop(); 27 28 Stopwatch sw1 = new Stopwatch(); 29 sw1.Start(); 30 ArrListTest(); 31 Console.WriteLine(" 使用非泛型ArrayList執行值類型方法歷時 : "+ sw1.Elapsed.ToString()); 32 sw1.Stop(); 33 Console.ReadLine();
通過循環 100 來比較,結果為 :

我們可以看到非泛型的時間要比泛型的時間多出0.0000523秒,泛型比非泛型的時間要多出一些, 那么我們將數值改動一下改為循環 1000次.得出結果為 :

將一個泛型算法應用於一個具體的類型時,編譯器和CLR能理解開發人員的意圖,並保證只有與指定數據類型兼容的對象才能隨同算法使用,若試圖使用不兼容類型的一個對象,會造成編譯時錯誤,或者運行時拋出異常
此篇至此,下篇主要知識點 :
1、泛型方法2、泛型接口3、泛型約束(主要約束,次要約束,構造器約束)4、泛型類型轉型5、泛型委托6、泛型和反射7、泛型和屬性
