前言:打算分三個層面來介紹這個知識點,分別是:.Net內建物件的擴充套件方法、一般物件的擴充套件方法、泛型物件的擴充套件方法。
什麼是擴充套件方法?回答這個問題之前,先看看我們一般情況下方法的呼叫。類似這樣的通用方法你一定寫過:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
static void Main(string[] args) { string strRes = "2013-09-08 14:12:10"; var dRes = GetDateTime(strRes); } //將字串轉換為日期 public static DateTime GetDateTime(string strDate) { return Convert.ToDateTime(strDate); } //得到非空的字串 public static string GetNotNullStr(string strRes) { if (strRes == null) return string.Empty; else return strRes; } |
或者在專案中有一個類似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方法放在同一個類中):
1 2 3 4 5 6 7 |
public static string GetNotNullStr(this string strRes) { if (strRes == null) return string.Empty; else return strRes ; } |
然後在Main方法裡面呼叫:
1 2 3 4 5 |
static void Main(string[] args) { string strTest = null; var strRes = strTest.GetNotNullStr(); } |
簡單介紹:public static string GetNotNullStr(this string strRes)其中this string就表示給string物件新增擴充套件方法。那麼在同一個名稱空間下面定義的所有的string型別的變數都可以.GetNotNullStr()這樣直接呼叫。strTest.GetNotNullStr();為什麼這樣呼叫不用傳引數,是因為strTest就是作為引數傳入到方法裡面的。你可以試試。使用起來就和.Net framework定義的方法一樣:
當然除了string,你可以給.Net內建的其他物件加擴充套件方法,例如給DataGridViewRow的擴充套件方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//DataGridViewRow的擴充套件方法,將當前選中行轉換為對應的物件 public static T ToObject<T>(this DataGridViewRow item) where T:class { var model = item.DataBoundItem as T; if (model != null) return model; var dr = item.DataBoundItem as System.Data.DataRowView; model = (T)typeof(T).GetConstructor(new System.Type[] { }).Invoke(new object[] { }); //反射得到泛型類的實體 PropertyInfo[] pro = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public); Type type = model.GetType(); foreach (PropertyInfo propertyInfo in pro) { if (Convert.IsDBNull(dr[propertyInfo.Name])) { continue; } if (!string.IsNullOrEmpty(Convert.ToString(dr[propertyInfo.Name]))) { var propertytype = propertyInfo.PropertyType; } } return model; } |
這樣看上去就像在擴充套件.Net Framework。有沒有感覺有點高大上~
2、一般物件的擴充套件方法
和Framework內建物件一樣,自定義的物件也可以增加擴充套件方法。直接上示例程式碼:
1 2 3 4 5 |
public class Person { public string Name { set; get; } public int Age { set; get; } } |
1 2 3 4 5 6 7 8 |
//Person的擴充套件方法,根據年齡判斷是否是成年人 public static bool GetBIsChild(this Person oPerson) { if (oPerson.Age >= 18) return false; else return true; } |
Main方法裡面呼叫:
1 2 3 |
var oPerson1 = new Person(); oPerson1.Age = 20; var bIsChild = oPerson1.GetBIsChild(); |
和string擴充套件方法類似,就不多做解釋了。
3、泛型物件的擴充套件方法
除了上面兩種之外,博主發現其實可以定義一個泛型的擴充套件方法。那麼,是不是所有的型別都可以直接使用這個擴充套件方法了呢?為了保持程式的嚴謹,下面的方法可能沒有實際意義,當開發中博主覺得可能存在這種場景:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public static class DataContractExtensions { //測試方法 public static T Test<T>(this T instance) where T : Test2 { T Res = default(T); try { Res.AttrTest = instance.AttrTest.Substring(0,2); //其他複雜邏輯... } catch { } return Res; } } public class Test2 { public string AttrTest { set; get; } } |
使用擴充套件方法有幾個值得注意的地方:
(1)擴充套件方法不能和呼叫的方法放到同一個類中
(2)第一個引數必須要,並且必須是this,這是擴充套件方法的標識。如果方法裡面還要傳入其他引數,可以在後面追加引數
(3)擴充套件方法所在的類必須是靜態類
(4)最好保證擴充套件方法和呼叫方法在同一個名稱空間下
可能你第一次使用這個會覺得很彆扭。你也許會說擴充套件方法和我以前用的static方法無論從程式碼實現還是演算法效率都差不多嘛,是的!確實差不多,但使用多了之後會發現它確實能幫你省去很多程式碼。