搜尋
首頁後端開發C#.Net教程C#的擴充方法解析

C#的擴充方法解析

Feb 07, 2017 pm 03:05 PM
c#

在使用物件導向的語言進行專案開發的過程中,較多的會使用到「繼承」的特性,但是並非所有的場景都適合使用「繼承」特性,在設計模式的一些基本原則中也有較多的提到。

繼承的有關特性的使用所帶來的問題:物件的繼承關係實在編譯時就定義好了,所以無法在執行時間改變從父類別繼承的實作。子類別的實作與它父類別有非常緊密的依賴關係,以至於父類別實作中的任何變更必然會導致子類別發生變化。

當你需要復用子類別時,如果繼承下來的實作不適合解決新的問題,則父類別必須重寫它或被其他更適合的類別替換,這種依賴關係限制了靈活性並最終限制了復用性。取代繼承特性的方式,較多的會採用 合成/聚合復用原則,「合成/聚合復用原則」:盡量使用合成/聚合,盡量不要使用類別繼承。

如果在新類型的物件應當攜帶有關額外行為的細節,在使用繼承特性時,有時可能不太適合,例如:處理指類型,密封類,或介面時。在面對這些要求時,我們有時會寫一些靜態類別包含一些靜態方法。但是過多的靜態方法會造成額外的不必要的開銷。

一.擴展方法概述:

面對以上的有關「繼承」的問題,以及在面對專案的一些需求時,我們需要解決這些問題的方式就是「擴展方法」。在C#3.0中引入了“擴展方法”,既有靜態方法的優點,又使調用它們的程式碼的可讀性得到了提高。在使用擴充方法時,可以像呼叫實例方法一樣呼叫靜態方法。

1.擴充方法的基本原則:

(1).C#只支援擴充方法,不支援擴充屬性、擴充事件、擴充操作符等。

(2).擴充方法(第一個參數前面是this的方法)必須在非泛型的靜態類別中聲明,擴充方法必須有一個參數,而且只有第一個參數使用this標記。

(3).C#編譯器尋找靜態類別中的擴充方法時,要求這些靜態類別本身必須具有檔案作用域。

(4).C#編譯要求「導入」擴充方法。 (靜態方法可以任意命名,C#編譯器在尋找方法時,需要花費時間進行查找,需要檢查文件作用域中的所有的靜態類,並掃描它們的所有靜態方法來查找一個匹配)

(5) .多個靜態類別可以定義相同的擴充方法。

(6).用一個擴充方法擴充一個型別時,同時也擴充了衍生型別。 

2.擴充方法宣告:

(1).必須在一個非嵌套的、非泛型型的靜態類別中(所以必須是一個靜態方法)

(2).至少有一個參數。

(3).第一個參數必須附加this關鍵字做前綴。

(4).第一個參數不能有其他任何修飾符(如ref或out)。

(5).第一個參數的型別不能是指標型別。

以上的兩個分類說明中,對擴展方法的基本特性和聲明方式做了一個簡單的介紹,有關擴展方法的使用方式,會在後面的代碼樣例中進行展示,再次就不再多做說明。

二.擴充方法原理解析:

「擴充方法」是C#獨有的一種方法,在擴充方法中會使用ExtensionAttribute這個attribute。

C#一旦使用this關鍵字標記了某個靜態方法的第一個參數,編譯器就會在內部向該方法應用一個定制的attribute,這個attribute會在最終生成的文件的元數據中持久性的儲存下來,此屬性在System.Core dll程式集中。

任何靜態類別只要包含了至少一個擴充方法,它的元資料中也會應用這個attribute,任何一個組件包含了至少一個符合上述特點的靜態類,它的元資料也會應用這個attribute。如果程式碼嗲用了一個不存在的實例方法,編譯器會快速的掃描引用的所有程序集,判斷它們哪些包含了擴展方法,然後,在這個程式集中,可以掃描包含了擴展方法的靜態類別。

如果同一個命名空間中的兩個類別含有擴展類型相同的方法,就沒有辦法做到只用其中一個類別中的擴充方法。為了透過類型的簡單名稱(沒有命名控制項前綴)來使用類型,可以匯入該類型所有在的命名空間,但這樣做的時候,你沒有辦法阻止那個命名空間中的擴充方法也被匯入進來。

三..NET3.5的擴展方法Enumerable和Queryable:

在框架中,擴展方法最大的用途就是為LINQ服務,框架提供了輔助的擴展方法,位於System.Linq命名空間下的Enumerable和Queryable類。 Enumerable大多數擴充是IEnumerable,Queryable大大多數擴充是IQueryable

1.Enumerable類別中的常用方法

(1).Range():一個參數是起始數,一個是要產生的結果數。

public static IEnumerable<int> Range(int start, int count) { 
            long max = ((long)start) + count - 1;
            if (count < 0 || max > Int32.MaxValue) throw Error.ArgumentOutOfRange("count"); 
            return RangeIterator(start, count);
        }
        static IEnumerable<int> RangeIterator(int start, int count) { 
            for (int i = 0; i < count; i++) yield return start + i;
}


(2).Where():对集合进行过滤的一个方式,接受一个谓词,并将其应用于原始集合中的每个元素。

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
            if (source == null) throw Error.ArgumentNull("source"); 
            if (predicate == null) throw Error.ArgumentNull("predicate"); 
            if (source is Iterator<TSource>) return ((Iterator<TSource>)source).Where(predicate);
if (source is TSource[]) return new WhereArrayIterator<TSource>((TSource[])source, predicate); 
if (source is List<TSource>) return new WhereListIterator<TSource>((List<TSource>)source, predicate);
            return new WhereEnumerableIterator<TSource>(source, predicate);
        }
 public WhereEnumerableIterator(IEnumerable<TSource> source, Func<TSource, bool> predicate) { 
                this.source = source;
                this.predicate = predicate; 
}


以上分别介绍了Range()和Where()两个方法,该类中还主要包含select()、orderby()等等方法。


2.Queryable类中的常用方法:


(1).IQueryable接口:


/// <summary>
  /// 提供对未指定数据类型的特定数据源的查询进行计算的功能。
  /// </summary>
  /// <filterpriority>2</filterpriority>
  public interface IQueryable : IEnumerable
  {
    /// <summary>
    /// 获取与 <see cref="T:System.Linq.IQueryable"/> 的实例关联的表达式目录树。
    /// </summary>
    /// 
    /// <returns>
    /// 与 <see cref="T:System.Linq.IQueryable"/> 的此实例关联的 <see cref="T:System.Linq.Expressions.Expression"/>。
    /// </returns>
    Expression Expression { get; }
    /// <summary>
    /// 获取在执行与 <see cref="T:System.Linq.IQueryable"/> 的此实例关联的表达式目录树时返回的元素的类型。
    /// </summary>
    /// 
    /// <returns>
    /// 一个 <see cref="T:System.Type"/>,表示在执行与之关联的表达式目录树时返回的元素的类型。
    /// </returns>
    Type ElementType { get; }
    /// <summary>
    /// 获取与此数据源关联的查询提供程序。
    /// </summary>
    /// 
    /// <returns>
    /// 与此数据源关联的 <see cref="T:System.Linq.IQueryProvider"/>。
    /// </returns>
    IQueryProvider Provider { get; }
  }


(2).Where():

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) { 
            if (source == null)
                throw Error.ArgumentNull("source"); 
            if (predicate == null)
                throw Error.ArgumentNull("predicate");
            return source.Provider.CreateQuery<TSource>(
                Expression.Call( 
                    null,
                    ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), 
                    new Expression[] { source.Expression, Expression.Quote(predicate) } 
                    ));
        }



(3).Select():

public static IQueryable<TResult> Select<TSource,TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector) {
            if (source == null)
                throw Error.ArgumentNull("source");
            if (selector == null) 
                throw Error.ArgumentNull("selector");
            return source.Provider.CreateQuery<TResult>( 
                Expression.Call( 
                    null,
                    ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TSource), typeof(TResult)), 
                    new Expression[] { source.Expression, Expression.Quote(selector) }
                    ));
}


以上是对扩展方法中两个类进行了一个简单的解析。


四.扩展方法实例:


由于扩展方法实际是对一个静态方法的调用,所以CLR不会生成代码对调用方法的表达式的值进行null值检查


1.异常处理代码:


  /// <summary>
    /// 为参数验证提供有用的方法
    /// </summary>
    public static class ArgumentValidator
    {
        /// <summary>
        /// 如果argumentToValidate为空,则抛出一个ArgumentNullException异常
        /// </summary>
        public static void ThrowIfNull(object argumentToValidate, string argumentName)
        {
            if (null == argumentName)
            {
                throw new ArgumentNullException("argumentName");
            }
            if (null == argumentToValidate)
            {
                throw new ArgumentNullException(argumentName);
            }
        }
        /// <summary>
        /// 如果argumentToValidate为空,则抛出一个ArgumentException异常
        /// </summary>
        public static void ThrowIfNullOrEmpty(string argumentToValidate, string argumentName)
        {
            ThrowIfNull(argumentToValidate, argumentName);
            if (argumentToValidate == string.Empty)
            {
                throw new ArgumentException(argumentName);
            }
        }
        /// <summary>
        /// 如果condition为真,则抛出ArgumentException异常
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="msg"></param>
        public static void ThrowIfTrue(bool condition, string msg)
        {
            ThrowIfNullOrEmpty(msg, "msg");
            if (condition)
            {
                throw new ArgumentException(msg);
            }
        }
        /// <summary>
        /// 如果指定目录存在该文件则抛出FileNotFoundException异常
        /// </summary>
        /// <param name="fileSytemObject"></param>
        /// <param name="argumentName"></param>
        public static void ThrowIfDoesNotExist(FileSystemInfo fileSytemObject, String argumentName)
        {
            ThrowIfNull(fileSytemObject, "fileSytemObject");
            ThrowIfNullOrEmpty(argumentName, "argumentName");
            if (!fileSytemObject.Exists)
            {
                throw new FileNotFoundException("&#39;{0}&#39; not found".Fi(fileSytemObject.FullName));
            }
        }
        public static string Fi(this string format, params object[] args)
        {
            return FormatInvariant(format, args);
        }
        /// <summary>
        /// 格式化字符串和使用<see cref="CultureInfo.InvariantCulture">不变的文化</see>.
        /// </summary>
        /// <remarks>
        /// <para>这应该是用于显示给用户的任何字符串时使用的“B”>“B”>“”。它意味着日志
        ///消息,异常消息,和其他类型的信息,不使其进入用户界面,或不会
        ///无论如何,对用户都有意义;).</para>
        /// </remarks>
        public static string FormatInvariant(this string format, params object[] args)
        {
            ThrowIfNull(format, "format");
            return 0 == args.Length ? format : string.Format(CultureInfo.InvariantCulture, format, args);
        }
        /// <summary>
        /// 如果时间不为DateTimeKind.Utc,则抛出ArgumentException异常
        /// </summary>
        /// <param name="argumentToValidate"></param>
        /// <param name="argumentName"></param>
        public static void ThrowIfNotUtc(DateTime argumentToValidate, String argumentName)
        {
            ThrowIfNullOrEmpty(argumentName, "argumentName");
            if (argumentToValidate.Kind != DateTimeKind.Utc)
            {
                throw new ArgumentException("You must pass an UTC DateTime value", argumentName);
            }
        }
}


2.枚举扩展方法:

public static class EnumExtensions
    {
        /// <summary>
        /// 获取名字
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public static string GetName(this Enum e)
        {
            return Enum.GetName(e.GetType(), e);
        }
        /// <summary>
        /// 获取名字和值
        /// </summary>
        /// <param name="enumType">枚举</param>
        /// <param name="lowerFirstLetter">是否转化为小写</param>
        /// <returns></returns>
        public static Dictionary<string, int> GetNamesAndValues( this Type enumType, bool lowerFirstLetter)
        {
//由于扩展方法实际是对一个静态方法的调用,所以CLR不会生成代码对调用方法的表达式的值进行null值检查
            ArgumentValidator.ThrowIfNull(enumType, "enumType");
            //获取枚举名称数组
            var names = Enum.GetNames(enumType);
            //获取枚举值数组
            var values = Enum.GetValues(enumType);
            var d = new Dictionary<string, int>(names.Length);
            for (var i = 0; i < names.Length; i++)
            {
                var name = lowerFirstLetter ? names[i].LowerFirstLetter() : names[i];
                d[name] = Convert.ToInt32(values.GetValue(i));
            }
            return d;
        }
        /// <summary>
        /// 转换为小写
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string LowerFirstLetter(this string s)
        {
            ArgumentValidator.ThrowIfNull(s, "s");
            return char.ToLowerInvariant(s[0]) + s.Substring(1);
        }
    }

五.总结:

在本文中,主要对扩展方法进行了一些规则说明、声明方式,使用方式,以及对扩展方法的意义和扩展方法的原理进行了简单的解答。并在本文的最后给了一个枚举的扩展方法代码。

以上就是C#的扩展方法解析的内容,更多相关内容请关注PHP中文网(www.php.cn)!


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
c#.net的持續相關性:查看當前用法c#.net的持續相關性:查看當前用法Apr 16, 2025 am 12:07 AM

C#.NET依然重要,因為它提供了強大的工具和庫,支持多種應用開發。 1)C#結合.NET框架,使開發高效便捷。 2)C#的類型安全和垃圾回收機制增強了其優勢。 3).NET提供跨平台運行環境和豐富的API,提升了開發靈活性。

從網絡到桌面:C#.NET的多功能性從網絡到桌面:C#.NET的多功能性Apr 15, 2025 am 12:07 AM

C#.NETisversatileforbothwebanddesktopdevelopment.1)Forweb,useASP.NETfordynamicapplications.2)Fordesktop,employWindowsFormsorWPFforrichinterfaces.3)UseXamarinforcross-platformdevelopment,enablingcodesharingacrossWindows,macOS,Linux,andmobiledevices.

C#.NET與未來:適應新技術C#.NET與未來:適應新技術Apr 14, 2025 am 12:06 AM

C#和.NET通過不斷的更新和優化,適應了新興技術的需求。 1)C#9.0和.NET5引入了記錄類型和性能優化。 2).NETCore增強了雲原生和容器化支持。 3)ASP.NETCore與現代Web技術集成。 4)ML.NET支持機器學習和人工智能。 5)異步編程和最佳實踐提升了性能。

c#.net適合您嗎?評估其適用性c#.net適合您嗎?評估其適用性Apr 13, 2025 am 12:03 AM

c#.netissutableforenterprise-levelapplications withemofrosoftecosystemdueToItsStrongTyping,richlibraries,androbustperraries,androbustperformance.however,itmaynotbeidealfoross-platement forment forment forment forvepentment offependment dovelopment toveloperment toveloperment whenrawspeedsportor whenrawspeedseedpolitical politionalitable,

.NET中的C#代碼:探索編程過程.NET中的C#代碼:探索編程過程Apr 12, 2025 am 12:02 AM

C#在.NET中的編程過程包括以下步驟:1)編寫C#代碼,2)編譯為中間語言(IL),3)由.NET運行時(CLR)執行。 C#在.NET中的優勢在於其現代化語法、強大的類型系統和與.NET框架的緊密集成,適用於從桌面應用到Web服務的各種開發場景。

C#.NET:探索核心概念和編程基礎知識C#.NET:探索核心概念和編程基礎知識Apr 10, 2025 am 09:32 AM

C#是一種現代、面向對象的編程語言,由微軟開發並作為.NET框架的一部分。 1.C#支持面向對象編程(OOP),包括封裝、繼承和多態。 2.C#中的異步編程通過async和await關鍵字實現,提高應用的響應性。 3.使用LINQ可以簡潔地處理數據集合。 4.常見錯誤包括空引用異常和索引超出範圍異常,調試技巧包括使用調試器和異常處理。 5.性能優化包括使用StringBuilder和避免不必要的裝箱和拆箱。

測試C#.NET應用程序:單元,集成和端到端測試測試C#.NET應用程序:單元,集成和端到端測試Apr 09, 2025 am 12:04 AM

C#.NET應用的測試策略包括單元測試、集成測試和端到端測試。 1.單元測試確保代碼的最小單元獨立工作,使用MSTest、NUnit或xUnit框架。 2.集成測試驗證多個單元組合的功能,常用模擬數據和外部服務。 3.端到端測試模擬用戶完整操作流程,通常使用Selenium進行自動化測試。

高級C#.NET教程:ACE您的下一次高級開發人員面試高級C#.NET教程:ACE您的下一次高級開發人員面試Apr 08, 2025 am 12:06 AM

C#高級開發者面試需要掌握異步編程、LINQ、.NET框架內部工作原理等核心知識。 1.異步編程通過async和await簡化操作,提升應用響應性。 2.LINQ以SQL風格操作數據,需注意性能。 3..NET框架的CLR管理內存,垃圾回收需謹慎使用。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境