C#基礎系列:擴充套件方法的使用
前言:打算分三個層面來介紹這個知識點,分別是:.Net內建物件的擴充套件方法、一般物件的擴充套件方法、泛型物件的擴充套件方法。
什麼是擴充套件方法?回答這個問題之前,先看看我們一般情況下方法的呼叫。類似這樣的通用方法你一定寫過:
C#123456789101112131415161718 | staticvoidMain(string[]args){stringstrRes="2013-09-08 14:12:10";vardRes=GetDateTime(strRes);}//將字串轉換為日期publicstaticDateTime GetDateTime(stringstrDate){returnConvert.ToDateTime(strDate);}//得到非空的字串publicstaticstringGetNotNullStr(stringstrRes |
或者在專案中有一個類似Utils的工具類,裡面有多個Helper,例如StringHelper、XmlHelper等等,每個Helper裡面有多個static的通用方法,然後呼叫的時候就是StringHelper.GetNotNullStr(“aa”);這樣。還有一種普通的用法就是new 一個物件,通過物件去呼叫類裡面的非static方法。反正博主剛開始做專案的時候就是這樣寫的。後來隨著工作經驗的累積,博主看到了擴充套件方法的寫法,立馬就感覺自己原來的寫法太Low了。進入正題。
1、.Net內建物件的擴充套件方法
.Net內部也有很多定義的擴充套件方法,例如我們Linq常用的Where(x=>x==true)、Select()等等。當你轉到定義的時候你很容易看出來:public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)。當然我們也可以給.Net物件新增擴充套件方法,比如我們要給string物件加一個擴充套件方法(注意這個方法不能和呼叫的Main方法放在同一個類中):
C#1234567 | publicstaticstringGetNotNullStr(thisstringstrRes){if(strRes==null)returnstring.Empty;elsereturnstrRes;} |
然後在Main方法裡面呼叫:
C#12345 | staticvoidMain(string[]args){stringstrTest=null;varstrRes=strTest.GetNotNullStr();} |
簡單介紹:public static string GetNotNullStr(this string strRes)其中this string就表示給string物件新增擴充套件方法。那麼在同一個名稱空間下面定義的所有的string型別的變數都可以.GetNotNullStr()這樣直接呼叫。strTest.GetNotNullStr();為什麼這樣呼叫不用傳引數,是因為strTest就是作為引數傳入到方法裡面的。你可以試試。使用起來就和.Net framework定義的方法一樣:
當然除了string,你可以給.Net內建的其他物件加擴充套件方法,例如給DataGridViewRow的擴充套件方法:
C#123456789101112131415161718192021222324 | //DataGridViewRow的擴充套件方法,將當前選中行轉換為對應的物件publicstaticTToObject<T>(thisDataGridViewRow 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;}}returnmodel;} |
這樣看上去就像在擴充套件.Net Framework。有沒有感覺有點高大上~
2、一般物件的擴充套件方法
和Framework內建物件一樣,自定義的物件也可以增加擴充套件方法。直接上示例程式碼:
C#12345 | publicclassPerson{publicstringName{set;get;}publicintAge{set;get;}} |
12345678 | //Person的擴充套件方法,根據年齡判斷是否是成年人publicstaticboolGetBIsChild(thisPerson oPerson){if(oPerson.Age>=18)returnfalse;elsereturntrue;} |
Main方法裡面呼叫:
C#123 | varoPerson1=newPerson();oPerson1.Age=20;varbIsChild=oPerson1.GetBIsChild(); |
和string擴充套件方法類似,就不多做解釋了。
3、泛型物件的擴充套件方法
除了上面兩種之外,博主發現其實可以定義一個泛型的擴充套件方法。那麼,是不是所有的型別都可以直接使用這個擴充套件方法了呢?為了保持程式的嚴謹,下面的方法可能沒有實際意義,當開發中博主覺得可能存在這種場景:
C#1234567891011121314151617181920 | publicstaticclassDataContractExtensions{//測試方法publicstaticTTest<T>(thisTinstance)whereT:Test2{TRes=default(T);try{Res.AttrTest=instance.AttrTest.Substring(0,2);//其他複雜邏輯...}catch{}returnRes;}}publicclassTest2{ publicstringAttrTest{set;get;}} |
使用擴充套件方法有幾個值得注意的地方:
(1)擴充套件方法不能和呼叫的方法放到同一個類中
(2)第一個引數必須要,並且必須是this,這是擴充套件方法的標識。如果方法裡面還要傳入其他引數,可以在後面追加引數
(3)擴充套件方法所在的類必須是靜態類
(4)最好保證擴充套件方法和呼叫方法在同一個名稱空間下
可能你第一次使用這個會覺得很彆扭。你也許會說擴充套件方法和我以前用的static方法無論從程式碼實現還是演算法效率都差不多嘛,是的!確實差不多,但使用多了之後會發現它確實能幫你省去很多程式碼。