【1】:泛型介紹
成都創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括鄲城網(wǎng)站建設(shè)、鄲城網(wǎng)站制作、鄲城網(wǎng)頁(yè)制作以及鄲城網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,鄲城網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到鄲城省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
泛型是C#2.0中一個(gè)重要的新特性,泛型是CLR和編程語(yǔ)言提供的一種特殊機(jī)制,它支持另一種形式的代碼重用。
泛型誕生之前:
C#是一種強(qiáng)類型的語(yǔ)言,在沒(méi)有泛型沒(méi)有被提出之前,我們?cè)谑褂眉系拇a的時(shí)候,每次對(duì)其進(jìn)行轉(zhuǎn)換都需要隱式的強(qiáng)制轉(zhuǎn)換,我們都知道所有對(duì)象的最終基類是object,我們?cè)诿看问褂胦bject的時(shí)候,無(wú)論是變換什么類型都要對(duì)其進(jìn)行強(qiáng)制轉(zhuǎn)換。
一般情況下,創(chuàng)建泛型類的過(guò)程為:從一個(gè)現(xiàn)有的具體類開(kāi)始,逐一將每個(gè)類型更改為類型參數(shù),直至達(dá)到通用化和可用性的最佳平衡。 創(chuàng)建您自己的泛型類時(shí),需要特別注意以下事項(xiàng):
將哪些類型通用化為類型參數(shù)。
通常,能夠參數(shù)化的類型越多,代碼就會(huì)變得越靈活,重用性就越好。 但是,太多的通用化會(huì)使其他開(kāi)發(fā)人員難以閱讀或理解代碼。
如果存在約束,應(yīng)對(duì)類型參數(shù)應(yīng)用什么約束
一條有用的規(guī)則是,應(yīng)用盡可能最多的約束,但仍使您能夠處理必須處理的類型。 例如,如果您知道您的泛型類僅用于引用類型,則應(yīng)用類約束。 這可以防止您的類被意外地用于值類型,并允許您對(duì) T 使用 as 運(yùn)算符以及檢查空值。
是否將泛型行為分解為基類和子類。
由于泛型類可以作為基類使用,此處適用的設(shè)計(jì)注意事項(xiàng)與非泛型類相同。 請(qǐng)參見(jiàn)本主題后面有關(guān)從泛型基類繼承的規(guī)則。
是否實(shí)現(xiàn)一個(gè)或多個(gè)泛型接口。
例如,如果您設(shè)計(jì)一個(gè)類,該類將用于創(chuàng)建基于泛型的集合中的項(xiàng),則可能必須實(shí)現(xiàn)一個(gè)接口,如 IComparable,其中 T 是您的類的類型。
【2】:泛型的表示方式
泛型可以為引用類型和值類型還有接口和委托,F(xiàn)CL( DLL程序集包含了.NET框架下的各種DLL )類中定義了一個(gè)泛型列表,用來(lái)管理一個(gè)對(duì)象集合,如果我們想要使用這個(gè)泛型列表,可以在使用時(shí)指定具體數(shù)據(jù)類型。
泛型的表示為 “T” 如:List<T>, T 表示一個(gè)未指定的數(shù)據(jù)類型,我們可以看一下FCL類中泛型的引用定義:
【3】:泛型的好處
1 : 使代碼更加的簡(jiǎn)潔,清晰
從前面我們也提到了,泛型具備可重用性 , 減少我們代碼量, 使我們的程序更容易開(kāi)發(fā)和維護(hù),舉例 :
舉例 1 : 在從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)庫(kù)的時(shí)候,我們經(jīng)常會(huì)返回一個(gè)DataTable類型,然后將其轉(zhuǎn)換為L(zhǎng)ist集合. 那么如果沒(méi)有泛型的話,我會(huì)一般會(huì)這樣來(lái)做.
public List<TrainingUser> GetTrainingUser(string userId) { DataTable dt = SqliteHelper.ExecuteDataset(System.Data.CommandType.Text, @" SELECT DISTINCT UserId,TrainingId FROM TRAININGUSER AS TU INNER JOIN [USER] AS U ON U.ID = TU.USERID JOIN [TRAINING] AS T ON T.ID = TU.TRAININGID WHERE U.ID = '"+userId+"' AND T.ENDTIME > DATETIME('now', 'localtime') AND T.StartTime <= DATETIME('now', 'localtime') ;").Tables[0]; return DataTableToList(dt); }
private List<TrainingUser> DataTableToList(DataTabledt) { List<TrainingUser> list = new List<TrainingUser>(); if(dt. Rows.Count > 0 ) { foreach (DataRow row in dt .Rows) { TrainingUser trainingUser = new TrainingUser(); if(row["UserId" ] != null) { trainingUser .UserId = row["UserId"].ToString(); } if(row["TrainingId" ] != null) { trainingUser.TrainingId = row["TrainingId"].ToString(); } list.Add(trainingUser); } } return list; }
在方法DataTableToList中,我們傳入了一個(gè)DataTable的對(duì)象,然后在去循環(huán)遍歷每一行的對(duì)象值從而去賦值給TrainingUser類型對(duì)象,這只是其中的一個(gè)方法,如果我們的類型還有 Training/User/Project等類型的話,我們是不是就要寫很多如同DataTableToList這樣的方法呢? 這就體現(xiàn)出了這樣的方式,會(huì)造成代碼的冗余以及維護(hù)不便問(wèn)題,那么我們使用泛型來(lái)解決
舉例 2 : 使用泛型使上面的代碼更見(jiàn)的清晰,簡(jiǎn)潔
public static List<T> ToList1<T>(DataTable dt) whereT : class, new() { var prlist =new List<PropertyInfo>(); Type type = typeof(T); Array.ForEach( type.GetProperties(), p => { if(dt.Columns.IndexOf(p.Name) !=-1) { prlist.Add(p); } }); var oblist = new List<T>(); // System.Data.SqlTypes. foreach(DataRow row in dt.Rows) { var ob = new T(); prlist.ForEach( p => { if(row[p.Name] != DBNull.Value) { p.SetValue(ob, row[p.Name], null); } }); oblist.Add(ob); } return oblist; }
在上面的這個(gè)方法中,我們定義了一個(gè)泛型方法,內(nèi)部實(shí)現(xiàn)中是使用了反射的原理,將DataTable轉(zhuǎn)換為了List(反射后續(xù)隨筆中總結(jié),此處只關(guān)注泛型部分即可),我們定義了一個(gè)靜態(tài)的返回值為L(zhǎng)ist<T> ,前面我們說(shuō)過(guò) T : 代表任意類型(枚舉除外),ToList1<T>,說(shuō)明我們?cè)谡{(diào)用這個(gè)方法的時(shí)候,同時(shí)要賦予方法名一個(gè)類型值,這個(gè)類型要和它的返回值類型一致(泛型是類型安全的),Where : 用于限制T的條件 ,例如 where T : class,new() 表示 T 只能是一個(gè)類,或者一個(gè)類型對(duì)象,那么我們?cè)谡{(diào)用的時(shí)候就可以這樣來(lái)
public List<TrainingUser>GetTrainingIdByUserId(string userId) { List<TrainingUser> trainingUserList = DataTableHelper.ToList1<TrainingUser>( SqliteHelper.ExecuteDataset(System.Data.CommandType.Text, @" SELECT DISTINCT UserId,TrainingId FROM TRAININGUSER AS TU INNER JOIN [USER] AS U ON U.ID = TU.USERID JOIN [TRAINING] AS T ON T.ID = TU.TRAININGID WHERE U.ID = '"+ userId +"' AND T.ENDTIME > DATETIME('now', 'localtime') AND T.StartTime <= DATETIME('now', 'localtime') ;").Tables[0]); return trainingUserList ; }
代碼中的DataTableHelper.ToList1<TrainingUser> 即為我們剛才所寫的一個(gè)泛型方法,這樣我們可以看到,ToList<T> 傳入的類型為TrainingUser,同時(shí)接收者為:List<T> = List<TrainingUser> ,
這樣即便我們后續(xù)還有Training/User/Project等其他的類型,我們都可以直接使用DataTableHelper.ToList1<T>(DataTable dt) 來(lái)進(jìn)行類型轉(zhuǎn)換.
2 : 提升程序的性能
泛型與非泛型相比較而言,性能要好一些,這是為什么? 首先,泛型的類型是由調(diào)用者(接收者),去直接賦值的(類型安全的), 那么就不會(huì)存在類型轉(zhuǎn)換的問(wèn)題,其次, 泛型減少了裝箱和拆箱的過(guò)程.
實(shí)例 3 : 對(duì)于值類型泛型與非泛型的性能比較
private static void ListTest() { List<int>list = new List<int>(); for(inti = 0; i < 100; i++) { list.Add(i); int a = list[i]; } list =null; } private static void ArrListTest() { ArrayList arr = new ArrayList(); for(inti = 0; i <100; i++) { arr.Add(i); int s = (int)arr[i]; } arr = null; }
Stopwatch sw = new Stopwatch(); sw.Start(); ListTest(); Console.WriteLine(" 使用泛型List執(zhí)行值類型方法歷時(shí) : "+ sw.Elapsed.ToString()); sw.Stop(); Stopwatch sw1 = new Stopwatch(); sw1.Start(); ArrListTest(); Console.WriteLine(" 使用非泛型ArrayList執(zhí)行值類型方法歷時(shí) : "+ sw1.Elapsed.ToString()); sw1.Stop(); Console.ReadLine();
通過(guò)循環(huán) 100 來(lái)比較,結(jié)果為 :
我們可以看到非泛型的時(shí)間要比泛型的時(shí)間多出0.0000523秒,泛型比非泛型的時(shí)間要多出一些, 那么我們將數(shù)值改動(dòng)一下改為循環(huán) 1000次.得出結(jié)果為 :
泛型比非泛型執(zhí)行的時(shí)間要短0.0000405秒
我們將時(shí)間在改動(dòng)一下,改為 100000呢?結(jié)果為 :
這次差距為 0.0054621 并且隨著執(zhí)行次數(shù)的增長(zhǎng),非泛型相比泛型的時(shí)間會(huì)逐步的增加,
通過(guò)反編譯我們也能看出 :
泛型:
非泛型
從編譯中我們也能看出泛型方法中,接收的為Int32,非泛型為Object,其次泛型不會(huì)進(jìn)行裝箱和拆箱操作,非泛型每次執(zhí)行都要進(jìn)行裝箱和拆箱操作.
3 : 類型安全
在實(shí)例1 , 2 ,3 中我們都有備注說(shuō)明,泛型的發(fā)送著必須要和接收者進(jìn)行一致,否則會(huì)報(bào)異常 ,例如 :
實(shí)例 4 :
講一個(gè)泛型算法應(yīng)用于一個(gè)具體的類型時(shí),編譯器和CLR能理解開(kāi)發(fā)人員的意圖,并保證只有與指定數(shù)據(jù)類型兼容的對(duì)象才能隨同算法使用,若試圖使用不兼容類型的一個(gè)對(duì)象,會(huì)造成編譯時(shí)錯(cuò)誤,或者運(yùn)行時(shí)拋出異常,
在值類型中,泛型要比非泛型的性能高出很多,在引用類型中,泛型和非泛型的性能相差無(wú)幾,但是代碼簡(jiǎn)潔了很多。
1、泛型接口
2、泛型委托
3、泛型約束(主要約束,次要約束,構(gòu)造器約束)
4、泛型類型轉(zhuǎn)型
5、泛型和反射
6、泛型和屬性
參考資料 :
CLR C# Via
深入理解C#
https://msdn.microsoft.com/zh-cn/library/sz6zd40f.aspx
https://msdn.microsoft.com/zh-cn/library/0x6a29h7.aspx
如果你覺(jué)得本文對(duì)你有幫助的話,請(qǐng)點(diǎn)右下角的推薦,或者直接關(guān)注我,后續(xù)將不斷更新.NET解析這一系列的文章....
新聞名稱:.NET泛型解析(上)
標(biāo)題來(lái)源:http://aaarwkj.com/article28/pdescp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供外貿(mào)建站、網(wǎng)頁(yè)設(shè)計(jì)公司、網(wǎng)站導(dǎo)航、響應(yīng)式網(wǎng)站、動(dòng)態(tài)網(wǎng)站、App設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)