學習Linq之前必須要了解的擴展方法
本文主要以下面幾個方面來詳細講解擴展方法:在C#3.0之前沒有擴展方法的狀態(或者你不會使用不知道擴展方法的時候)、擴展方法的語法及怎麽使用、怎麽正確的使用擴展方法;
一、首先說一下在C#3.0之前沒有擴展方法的狀態(或者你不會使用不知道擴展方法的時候)
1、大家在項目中肯定遇到類似這樣的需求且項目很多地方都會用到:1.需要對一個對象進行可空判斷;2、對一個集合或者對象進行序列化;3、時間格式轉換;4、List與DataTabel之前轉換等等。
我想在沒有擴展方法之前大家基本上都是做一個類似common的靜態公共靜態類,寫一些靜態方法供項目各個調用調用 如:
public static class Common { /// <summary> /// 判斷是否為Null或者空 /// </summary> /// <param name="obj">對象</param> /// <returns></returns> public static bool IsNullOrEmpty( object obj) { if (obj == nullView Code) return true; else { string objStr = obj.ToString(); return string.IsNullOrEmpty(objStr); } } }
其他類調用公共方法
static void Main(string[] args) { stringView Codestr = "lxsh"; Common.IsNullOrEmpty(str); }
通過這樣也能完成上面所說的幾個需求,但是讓人感覺上端一直要顯示依賴Common這個靜態類,項目中就會大量充斥著這樣的代碼,看起來不那麽簡潔,而且也不利於後期的鏈式語法編程;
2、有時也會遇到這樣的情況:你想對某個類型加一些行為(方法),但你不能改變該類型的本身,因為是別人的代碼,遇到這樣情況你可能會增加一個繼承接口,或者一個抽象類,或者通過代理模式封裝一次,這樣顯然能達到目的但都很麻煩;
以上解決辦法都是在沒有使用擴展方法之前的解決方案,當你學會了擴展方法,你可能會有更好的選擇;
二、 接下來我們來說一下擴展方法的語法及使用
1、擴展方法必須具備以下幾個特征:
- 必須是在非嵌套的、非泛型的靜態類中
- 必須在靜態類中的靜態方法
- 至少要有一個參數
- 第一個參數的前綴必須加this關鍵字且不能有任何修飾符(如:ref,out)且參數類型不能為指針
例如:
public static partial class Extensions { public static string ObjectToJSON(this object obj) { return JsonConvert.SerializeObject(obj, new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" }); } /// <summary> /// 判斷是否為Null或者空 /// </summary> /// <param name="obj">對象</param> /// <returns></returns> public static bool IsNullOrEmpty(this object obj) { if (obj == null) return true; else { string objStr = obj.ToString(); return string.IsNullOrEmpty(objStr); } } }View Code
2、怎麽使用擴展方法:
先引用擴展方法靜態類所在的命名空間,引用完成後,在調用的時候它在你對應類型實例上面有”智能感知“提示
3、擴展方法是怎麽被發現調用的
如果在using命令,將擴展方法引用到代碼中,擴展方法可以像類一下不加限制地在代碼中使用。如果編譯器認為一個表達試好像要使用一個實例方法,但沒有找到與這個方法調用兼容的實例方法,就會查找一個合適的擴展方法。它會檢查導入的所有命名空間和當前命名空間中所有的擴展方法,並匹配那些從表達式類型到擴展類型存在隱式轉換的擴展方法;
簡單一句話講:編譯器首先會查看這類型(包括父類)有沒有對應的該實例方法,如果有該實例方法他就不會執行擴展方法,如果沒有它就會找對應的擴展方法執行;
假如有一個 student類,它有一個實例方法say,再給他加一個擴展方法say
public class Student { public void Say() { Console.WriteLine("我是實例方法"); } } public static class Extensions { public static void Say(this Student student) { Console.WriteLine("我是擴展方法"); } }View Code
static void Main(string[] args) { Student student = new Student(); student.Say(); Console.ReadKey(); }View Code
執行結果為:
還有一種情況,對子類和父類同時加了一個一樣的擴展方法,且都引用了他們名詞空間,優先調用子類的擴展方法(同樣適用於接口父子關系)
public class Person { } public class Student:Person { public void Say() { Console.WriteLine("我是實例方法"); } } public static class Extensions { public static void Say(this Student student) { Console.WriteLine("我是擴展方法"); } public static void GetName(this Student student) { Console.WriteLine("我是子類擴展方法"); } public static void GetName(this Person student) { Console.WriteLine("我是父類擴展方法"); } }View Code
static void Main(string[] args) { Student student = new Student(); student.Say(); student.GetName(); Console.ReadKey(); }View Code
執行結果:
三、怎麽正確的使用擴展方法(建議)
接下來簡單講一下怎麽正確使用擴展方法:
1.如果在項目中使用擴展方法,首先需要要項目成員都熟悉擴展方法的使用
2.將擴展方法單獨放到一個單獨的命名空間裏,可有效的防止被誤用,建議擴展方法所屬擴展類盡量用partial類(如針對Object的擴展方法命名Extensions.Object、針對string的擴展方法命名Extensions.String),方便代碼維護
例如:Extensions.Object、Extensions.String
namespace Lucky.Proect.Core.Extensions { public static partial class Extensions { public static string ObjectToJSON(this object obj) { return JsonConvert.SerializeObject(obj, new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-dd HH:mm:ss" }); } /// <summary> /// 判斷是否為Null或者空 /// </summary> /// <param name="obj">對象</param> /// <returns></returns> public static bool IsNullOrEmpty(this object obj) { if (obj == null) return true; else { string objStr = obj.ToString(); return string.IsNullOrEmpty(objStr); } } } }View Code
namespace Lucky.Proect.Core.Extensions { public static partial class Extensions { [DebuggerStepThrough] //該特性是用在方法前面的,在想要跳過的方法前面加上 public static T FromJson<T>(this string jsonStr) { return string.IsNullOrEmpty(jsonStr) ? default(T) : JsonConvert.DeserializeObject<T>(jsonStr); } /// <summary> /// 指示指定的字符串是 null、空或者僅由空白字符組成。 /// </summary> [DebuggerStepThrough] //該特性是用在方法前面的,在想要跳過的方法前面加上 public static bool IsNullOrWhiteSpace(this string value) { return string.IsNullOrWhiteSpace(value); } /// <summary> /// 將Json字符串轉為DataTable /// </summary> /// <param name="jsonStr">Json字符串</param> /// <returns></returns> public static DataTable ToDataTable(this string jsonStr) { return jsonStr == null ? null : JsonConvert.DeserializeObject<DataTable>(jsonStr); } } }View Code
3.盡量不在在object上面寫太多的擴展方法,寫之前要多加思考,不然在項目使用中任何類型智能提示出現一推擴展方法,看起來比較雜亂,針對int的擴展方法應該寫在int類型上,針對datetime的擴展方法應該寫在datetime類型上不應該都寫在object類型上
4.如果方法名在擴展類型中已經使用,就不要再用這個名稱了,因為寫了也無效;
學習Linq之前必須要了解的擴展方法