深入理解C#中的擴(kuò)展方法
擴(kuò)展方法(Extension Methods)是C#3.0時(shí)引入的新特性,相信很多人都聽過并且也都用過,最常見的是在LINQ中的使用。
不僅如此,在開發(fā)中,我們也可以創(chuàng)建自己擴(kuò)展方法,使用它來優(yōu)化類的設(shè)計(jì)、簡(jiǎn)化代碼。本文將簡(jiǎn)單地介紹擴(kuò)展方法的概念、定義、使用場(chǎng)景以及要注意的點(diǎn)。
一、概念
擴(kuò)展方法是一種特殊類型的靜態(tài)方法。對(duì)于一個(gè)C#類型,如類(包括密封類)、值類型、接口等,擴(kuò)展方法可以在不改變?cè)擃愋驮创a的前提下,為它的實(shí)例提供新的成員。因此,若要為一個(gè)框架或第三方庫的某個(gè)類型增加輔助功能,通過擴(kuò)展方法就可以輕而易舉地實(shí)現(xiàn),這也是“擴(kuò)展”的意義所在。
二、如何定義
創(chuàng)建擴(kuò)展方法很簡(jiǎn)單,有以下幾個(gè)步驟:
1、創(chuàng)建一個(gè)靜態(tài)類;
2、在其中創(chuàng)建一個(gè)靜態(tài)方法;
3、為這個(gè)靜態(tài)方法添加至少一個(gè)參數(shù),并在第一個(gè)參數(shù)前加上this關(guān)鍵字,這個(gè)關(guān)鍵字會(huì)告訴編譯器當(dāng)前方法是一個(gè)擴(kuò)展方法。而這個(gè)方法將成為第一個(gè)參數(shù)所屬類型的新成員。
以下一個(gè)典型的擴(kuò)展方法,用于為枚舉值提供一個(gè)可獲取其DescriptionAttribute特性值的方法:
namespace TLA. Infrastructure. Extensions public static class EnumExtensions { public static string GetDescription(this Enum en) { Type type = en. GetType(); MemberInfo[] memInfo = type . GetMember(en. ToString()); if (memInfo != null && memInfo.Length > 0) { object[] attrs = memInfo[0] . GetCustomAttributes (typeof (DescriptionAttribute), false); if (attrs != null && attrs. Length > 0){ return ( (DescriptionAttribute )attrs [0]) . Description; } } return en. ToString(); } } }
注意:只有在引用擴(kuò)展方法所在的靜態(tài)類的命名空間后,才能使用它;否則,直接調(diào)用會(huì)編譯失敗。上例中,使用該擴(kuò)展方法要引用TLA.Infrastructure.Extensions命名空間。
三、何時(shí)使用
從擴(kuò)展方法的概念上,不難看出,它可以用在以下幾種場(chǎng)合:
1、要為某個(gè)類型擴(kuò)展功能,但沒有其源碼,比如某個(gè)框架或第三方庫中的一個(gè)類;例如,想要獲取一個(gè)列表中所有的奇數(shù)項(xiàng),就可以為IList<T>接口增加一個(gè)擴(kuò)展方法,這里的IList<T>接口本身是.NET框架中的接口。
public static class IListExtentions { public static IEnumerable<T> OddItems<T>(this IEnumerable<T> list) { if (list == nu1l) { throw new ArgumentNullExcept ion (nameof(list)) ; } for (int i = 0; i < list. Count(); i++) { if(i%2==0) { yield return list. ElementAt(i); } } } }
2、即使可以訪問原有類型的源碼,也可以使用擴(kuò)展方法為它添加輔助功能;
public interface ILog { void Log(string message, LogLevel logLevel); } public static class ILogExtensions { /// <summary> ///記錄調(diào)試信息 /// </summary> /// <remarks>擴(kuò) 展方法,方便記錄調(diào)試信息</ remarks> public static void LogDebug(this ILog logger, string message ) { if (true) // 判斷日志配置中是否允許輸入Debug類型的日志 { logger? .Log($" {message}", LogLevel.Debug); } } }
3、重用代碼,使代碼更簡(jiǎn)潔;由于擴(kuò)展方法封裝了一段完整的邏輯,所以,使用擴(kuò)展方法就避免了復(fù)制粘貼代碼的情況。上例中擴(kuò)展方法的內(nèi)容也符合這種使用場(chǎng)景。
四、注意事項(xiàng)
以下是定義與使擴(kuò)展方法時(shí)的一些注意事項(xiàng)和最佳實(shí)踐:
1、擴(kuò)展方法本質(zhì)上是為原有類型提供輔助功能,因此,在創(chuàng)建時(shí),要確保它具有實(shí)際意義,且遵循單一職責(zé)原則;也即,不能過度使用擴(kuò)展方法并且它能夠完成一個(gè)具體、完整的功能;
2、擴(kuò)展方法本身具有通用性,因此,它里面應(yīng)避免特定的業(yè)務(wù)數(shù)據(jù)類型及其相關(guān)邏輯;
3、如果為接口增加擴(kuò)展方法,擴(kuò)展方法的命名空間可以與接口的一致;否則,應(yīng)盡量避免與原類型寫在同一命名空間下,這樣會(huì)“污染”原類型。建議的做法是為擴(kuò)展方法所在的類設(shè)定一個(gè)單獨(dú)的命名空間,如:<Company>.<Product>.Extentions。不過,這樣做也有缺點(diǎn):在操作原有類型的實(shí)例時(shí),如果不引用擴(kuò)展方法所在的命名空間,那么,它就不容易被發(fā)現(xiàn),而解決這個(gè)問題的辦法是,盡量將擴(kuò)展方法文檔化,并告訴項(xiàng)目組的其他開發(fā)人員;
4、為接口增加擴(kuò)展方法后,則所有實(shí)現(xiàn)此接口的類都會(huì)包含該擴(kuò)展方法;
5、在擴(kuò)展方法中,要對(duì)第一個(gè)參數(shù)進(jìn)行非空檢查,如果為空,應(yīng)拋出ArgumentNullException(參數(shù)為空)異常。
相關(guān)文章
C# Double轉(zhuǎn)化為String時(shí)的保留位數(shù)及格式方式
這篇文章主要介紹了C# Double轉(zhuǎn)化為String時(shí)的保留位數(shù)及格式方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02C#訪問SqlServer設(shè)置鏈接超時(shí)的方法
這篇文章主要介紹了C#訪問SqlServer設(shè)置鏈接超時(shí)的方法,涉及CommandTimeout屬性的相關(guān)設(shè)置技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-06-06Winform學(xué)生信息管理系統(tǒng)登陸窗體設(shè)計(jì)(1)
這篇文章主要為大家詳細(xì)介紹了Winform學(xué)生信息管理系統(tǒng)登陸窗體設(shè)計(jì)思路,感興趣的小伙伴們可以參考一下2016-05-05C#實(shí)現(xiàn)六大設(shè)計(jì)原則之迪米特法則
這篇文章介紹了C#實(shí)現(xiàn)六大設(shè)計(jì)原則之迪米特法則的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-02-02