1. 程式人生 > >C#基礎系列:小話泛型

C#基礎系列:小話泛型

前言:這一章來總結下C#泛型技術的使用。據博主的使用經歷,覺得泛型也是為了重用而生的,並且大部分時候會和反射一起使用。這次還是打算圍繞WWH(即What、Why、How)來講解。

1、什麼是泛型:通過引數化型別來實現在同一份程式碼上操作多種資料型別。利用“引數化型別”將型別抽象化,從而實現靈活的複用。怎麼理解呢,其實根據博主的理解,泛型就是將型別抽象化,使用抽象化的型別或物件去實現某些功能和業務,然後所有需要使用這些功能和業務的具體型別去呼叫泛型的方法和委託。呵呵,是不是還是有點暈,彆著急,我們來個例子:

我們首先來定義一種場景:我們通過sql語句使用Ado.Net來查詢預設得到的是弱型別的DataTable、DataReader等,而我們需要對查詢到的結果集使用lamada表示式進行某些複雜的計算,需要將DataTable轉換為對應的List<T>集合,首先來定義一個泛型的方法:

C#
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 publicstaticList<T>GetListByDateTable<T>(DataTable dt){List<T>modelList=newList<T>();try{//1.如果DataTable沒有資料則直接返回if(dt==
null||dt.Rows.Count==0){returnmodelList;}//2.遍歷DataTable填充實體varlstCol=dt.Columns;foreach(DataRow dr indt.Rows){Tmodel=default(T);//如果是object(這種一般用於一個實體類表示不了的情況),則先拼接json再反序列化為objectif(typeof(T).Equals(typeof(object))){varstrJson="{";foreach(DataColumn oCol inlstCol){varoAttrValue=Convert.IsDBNull(dr[oCol.ColumnName])?null:dr[oCol.ColumnName];strJson+="\""+oCol.ColumnName+"\":\""+oAttrValue+"\",";}strJson=strJson.ToString().Trim(',')+"}";model=E2ERes.JavaScriptStrToObj<T>(strJson);}else{model=FillEntityByDT<T>(dt,dr);}modelList.Add(model);}}catch{}returnmodelList;}//通過DataTable填充實體類privatestaticTFillEntityByDT<T>(DataTable dt,DataRow dr){Tmodel=(T)typeof(T).GetConstructor(newSystem.Type[]{}).Invoke(newobject[]{});//反射得到泛型類的實體PropertyInfo[]pro=typeof(T).GetProperties(BindingFlags.Instance|BindingFlags.Public);Type type=model.GetType();foreach(PropertyInfo propertyInfo inpro){if(dt.Columns.Contains(propertyInfo.Name)){if(Convert.IsDBNull(dr[propertyInfo.Name])){continue;}if(!string.IsNullOrEmpty(Convert.ToString(dr[propertyInfo.Name]))){type.GetProperty(propertyInfo.Name).SetValue(model,dr[propertyInfo.Name],null);}}}returnmodel;}

有了這個泛型的方法,我們在轉換DataTable和具體的List<Model>的時候是不是就是一個很好的複用。

2、為什麼要使用泛型:博主記得剛參加工作的前兩年有一次面試的時候就被問到“泛型有什麼優勢?”,當時怎麼回答的不記得了,只知道面試不太順利~~為什麼要用泛型呢?博主覺得泛型的主要優勢有以下幾點:

(1)保證了型別的安全性:泛型約束了變數的型別,保證了型別的安全性。例如List<int>和ArrayList。List<int>集合只能加入int型別的變數,ArrayList可以Add任何常用型別,編譯的時候不會提示錯誤。

(2)避免了不必要的裝箱、拆箱操作,提高程式的效能:泛型變數固定了型別,使用的時候就已經知道是值型別還是引用型別,避免了不必要的裝箱、拆箱操作。舉例說明:

使用泛型之前,我們使用object代替。

C#
123 objecta=1;//由於是object型別,會自動進行裝箱操作。intb=(int)a;//強制轉換,拆箱操作。這樣一去一來,當次數多了以後會影響程式的執行效率。

使用泛型之後

C#
123456789 publicstaticTGetValue<T>(Ta){  returna;}publicstaticvoidMain(){  intb=GetValue<int>(1);//使用這個方法的時候已經指定了型別是int,所以不會有裝箱和拆箱的操作。}

(3)提高方法、演算法的重用性。上面的例子基本能說明這個優勢。

3、泛型的使用:

(1)泛型方法的使用:這也是博主使用最多的用法之一,像這種泛型方法一般是一些static的通用方法,例如原來專案中用到的一個將DataGridViewRow物件轉換成對應的實體Model的方法如下:

C#
123456789101112131415161718192021222324252627282930313233343536373839404142 publicstaticTToObject<T>(DataGridViewRow item)whereT:class{varmodel=item.DataBoundItem asT;if(model!=null)returnmodel;vardr=item.DataBoundItem asSystem.Data.DataRowView;model=(T)typeof(T).GetConstructor(newSystem.Type[]{}).Invoke(newobject[]{});//反射得到泛型類的實體PropertyInfo[]pro=typeof(T).GetProperties(BindingFlags.Instance|BindingFlags.Public);Type type=model.GetType();foreach(PropertyInfo propertyInfo inpro){if(Convert.IsDBNull(dr[propertyInfo.Name])){continue;}if(!string.IsNullOrEmpty(Convert.ToString(dr[propertyInfo.Name]))){varpropertytype=propertyInfo.PropertyType;if(propertytype==typeof(System.Nullable<DateTime>)||propertytype==typeof(DateTime)){type.GetProperty(propertyInfo.Name).SetValue(model,Convert.ToDateTime(dr[propertyInfo.Name]),null);}elseif(propertytype==typeof(System.Nullable<decimal>)||propertytype==typeof(decimal)){type.GetProperty(propertyInfo.Name).SetValue(model,Convert.ToDecimal(dr[propertyInfo.Name]),null);}elseif(propertytype==typeof(System.Nullable<int>)||propertytype==typeof(int)){type.GetProperty(propertyInfo.Name).SetValue(model,Convert.ToInt32(dr[propertyInfo.Name]),null);}elseif(propertytype==typeof(System.Nullable<double>)||propertytype==typeof(double)){type.GetProperty(propertyInfo.Name).SetValue(model,Convert.ToDouble(dr[propertyInfo.Name]),null);}else{type.GetProperty(propertyInfo.Name).SetValue(model,dr[propertyInfo.Name],null);}}}returnmodel;}

使用泛型方法的注意事項:

  • 泛型方法的過載:public void Fun1<T>(T a);和public void Fun1<U>(U a);是無法過載的,這其實很好理解,因為T和U其實都是泛型的一個代表符號而已;
  • 泛型方法的重寫:下面的方法重寫FuncA的重寫是正確的,FuncB的重寫不正確,因為約束被預設繼承,不用再寫。
C#
12345678910 abstractclassBaseClass{publicabstractTFuncA<T,U>(Tt,Uu)whereU:T;publicabstractTFuncB<T>(

相關推薦

C#基礎系列

前言:這一章來總結下C#泛型技術的使用。據博主的使用經歷,覺得泛型也是為了重用而生的,並且大部分時候會和反射一起使用。這次還是打算圍繞WWH(即What、Why、How)來講解。 1、什麼是泛型:通過引數化型別來實現在同一份程式碼上操作多種資料型別。利用“引數化型別

C#基礎系列——

前言:前面兩章介紹了C#的兩個常用技術:C#基礎系列——反射筆記 和 C#基礎系列——Attribute特性使用 。這一章來總結下C#泛型技術的使用。據博主的使用經歷,覺得泛型也是為了重用而生的,並且大部分時候會和反射一起使用。這次還是打算圍繞WWH(即What、Why、How)來講解。 1、什麼是泛型

Go基礎系列數據類轉換(strconv包)

丟失 ror 什麽 可能 進位 自然 parsing out a-z Go不會對數據進行隱式的類型轉換,只能手動去執行轉換操作。 簡單的轉換操作 轉換數據類型的方式很簡單。 valueOfTypeB = typeB(valueOfTypeA) 例如: // 浮點數 a :=

C#基礎系列Attribute特性使用

前言:總結了下反射得基礎用法,這章我們來看看C#的另一個基礎技術——特性。 1、什麼是特性:就博主的理解,特性就是在類的類名稱、屬性、方法等上面加一個標記,使這些類、屬性、方法等具有某些統一的特徵,從而達到某些特殊的需要。比如:方法的異常捕捉,你是否還在某些可能出現

C#基礎系列非同步程式設計初探async和await

前言:前面有篇從應用層面上面介紹了下多執行緒的幾種用法,有博友就說到了async, await等新語法。確實,沒有非同步的多執行緒是單調的、乏味的,async和await是出現在C#5.0之後,它的出現給了非同步並行變成帶來了很大的方便。非同步程式設計涉及到的東西還

C#基礎系列序列化效率比拼

      前言:作為開發人員,物件的序列化恐怕難以避免。樓主也是很早以前就接觸過序列化,可是理解都不太深刻,對於用哪種方式去做序列化更是隨波逐流——專案中原來用的什麼方式照著用就好了。可是這麼多年自己對於這東西還是挺模糊的,今天正好有時間,就將原來用過的幾種方式總結了下,也算是做一個記錄,順便做了下效能測

C#基礎系列反射筆記

前言:使用反射也有幾年了,但是一直覺得,反這個概念很抽象,今天有時間就來總結下這個知識點。 1、為什麼需要反射: 最初使用反射的時候,作為小菜總是不理解,既然可以通過new 一個物件的方式得到物件,然後通過物件去呼叫屬性和方法,那麼為什麼還需要反射去呼叫呢?後來使用

C#基礎系列委託實現簡單設計模式(1)

前言:這篇簡單介紹下委託的使用。當然啦,園子裡面很多介紹委託的文章都會說道:委託和事件的概念就像一道坎,過了這個檻的人,覺得真是太容易了,而沒有過去的人每次見到委託和事件就覺得心裡發慌。確實這東西就像最開始學C語言的指標一樣,令人有一種很糾結的感覺,總覺得要呼叫一個

C#基礎系列委託和設計模式(2)

前言:這篇打算從設計模式的角度去解析下委託的使用。我們知道使用委託可以實現物件行為(方法)的動態繫結,從而提高設計的靈活性。上次說過,方法可以理解為委託的例項,站在方法的層面,委託例項的一個非常有用的特性是它既不知道,也不關心其封裝方法所屬類的詳細資訊,對它來說最重

C#基礎系列再也不用擔心面試官問我“事件”了

前言:作為.Net攻城獅,你面試過程中是否遇到過這樣的問題呢:什麼是事件?事件和委託的區別?既然事件作為一種特殊的委託,那麼它的優勢如何體現?諸如此類…你是否也曾經被問到過?你又是否都答出來了呢? 關於面試中涉及到的事件的問題,我們只需要抓住幾個關鍵點就好了: (1

C#基礎系列擴充套件方法的使用

前言:打算分三個層面來介紹這個知識點,分別是:.Net內建物件的擴充套件方法、一般物件的擴充套件方法、泛型物件的擴充套件方法。 什麼是擴充套件方法?回答這個問題之前,先看看我們一般情況下方法的呼叫。類似這樣的通用方法你一定寫過:

C#基礎系列Linq to Xml讀寫xml

前言:xml的操作方式有多種,但要論使用頻繁程度,博主用得最多的還是Linq to xml的方式,覺得它使用起來很方便,就用那麼幾個方法就能完成簡單xml的讀寫。之前做的一個專案有一個很變態的需求:C#專案呼叫不知道是什麼語言寫的一個WebService,然後新增服

C#基礎系列多執行緒的常見用法詳解

前言:此篇就主要從博主使用過的幾種多執行緒的用法從應用層面大概介紹下。文中觀點都是博主個人的理解,如果有不對的地方望大家指正~~ 1、多執行緒:使用多個處理控制代碼同時對多個任務進行控制處理的一種技術。據博主的理解,多執行緒就是該應用的主執行緒任命其他多個執行緒去協

C#基礎系列開發自己的窗體設計器(PropertyGrid顯示中文屬性名)

  既然是一個窗體設計器,那就應該能夠設定控制元件的屬性,設定屬性最好的當然是PropertyGrid了,我們僅僅需要使用一個PropertyGrid.SelectedObject = Control就可以搞定,讓PropertyGrid顯示Control的所有屬性。可是這

C#基礎知識(八)

泛型的好處很多,包括複用性(可供多個型別使用而不用每個型別都定義一次),型別安全(不合法的型別報錯),高效率(減少裝箱和拆箱) 舉例: 假設我們有一個父類Animal,所有動物繼承這個類,現在需要做一個比較動物重量的方法,如果不用泛型,則我們隊沒類動物都需要過載一次比較的方

【一天一個基礎系列】- java之

### 簡介 + 說起各種高階語言,不得不談泛型,當我們在使用java集合的時候,會發現集合有個缺點:把一個物件“丟進”集合之後,集合就會“忘記”這個物件的資料型別,當再次取出該物件時,改物件的編譯型別就變成了`Object`型別 + 問題1:集合對元素型別沒有任何限制,這樣可能會引發一些問題,比如建立一個

C# 基礎知識系列- 10 反射和(二)

0. 前言 這篇文章延續《C# 基礎知識系列- 5 反射和泛型》,繼續介紹C#在反射所開發的功能和做的努力。上一篇文章大概介紹了一下泛型和反射的一些基本內容,主要是通過獲取物件的型別,然後通過這個型別物件操作物件。這一篇介紹一個在反射中很重要的內容:特性,以及上一篇未完成的內容——泛型在反射中的引用。 1.

JavaScript 基礎知識系列數據類及slice(8,-1)

測試 因此 針對 apply() 3.1 正則 gin fine ray 在基礎類庫中常見的slice(8,-1)是個什麽鬼?下面就從js數據類型說起。 javascrip數據類型有兩種: 基本類型:Undefined,Null,Boolean,Number,String

【JAVA】基礎集合、、異常、反射

1.集合 集合就是高階陣列,可以存放任意型別的物件,同時可以自動擴容。 集合主要由兩個介面派生而出:Collection和Map Iterator 介面: 是Collection介面的父介面,主要是用於遍歷Collection中的元素。 語法: //構造 Li

C#基礎系列——一場風花雪月的邂逅介面和抽象類

前言:最近一個認識的朋友準備轉行做程式設計,看他自己邊看視訊邊學習,挺有幹勁的。那天他問我介面和抽象類這兩個東西,他說,既然它們如此相像, 我用抽象類就能解決的問題,又整個接口出來幹嘛,這不是誤導初學者嗎。博主呵呵一笑,回想當初的自己,不也有此種疑惑麼。。。今天打算針對他的問題,結合一個實際的使用場景來說明下