<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        詳談.NET的異常處理

        來源:懂視網 責編:小采 時間:2020-11-27 22:36:14
        文檔

        詳談.NET的異常處理

        詳談.NET的異常處理:年關將至,對于大部分程序員來說,馬上就可以閑下來一段時間了,然而在這個閑暇的時間里,唯有爭論哪門語言更好可以消磨時光,估計最近會有很多關于java與.net的博文出現,我表示要作為一個吃瓜群眾,靜靜的看著大佬們發表心情。 以上的廢話說的夠多了,這里
        推薦度:
        導讀詳談.NET的異常處理:年關將至,對于大部分程序員來說,馬上就可以閑下來一段時間了,然而在這個閑暇的時間里,唯有爭論哪門語言更好可以消磨時光,估計最近會有很多關于java與.net的博文出現,我表示要作為一個吃瓜群眾,靜靜的看著大佬們發表心情。 以上的廢話說的夠多了,這里

        年關將至,對于大部分程序員來說,馬上就可以閑下來一段時間了,然而在這個閑暇的時間里,唯有爭論哪門語言更好可以消磨時光,估計最近會有很多關于java與.net的博文出現,我表示要作為一個吃瓜群眾,靜靜的看著大佬們發表心情。

        以上的廢話說的夠多了,這里就不再廢話了,還是切入正題吧。

        在項目開發中,對于系統和代碼的穩定性和容錯性都是有對應的要求。實際開發項目中的代碼與樣例代碼的區別,更多的是在代碼的運行的穩定性、容錯性、擴展性的比較。因為對于實現一個功能來說,實現功能的核心代碼是一樣的,可能只是在寫法上優化而已,但是在實現某一個操作上使用的類來說,這一點是絕大多數時候是一樣的。這樣看來,我們在實際開發的過程中,需要考慮的問題比較多,已經不僅僅局限于某一具體的功能實現,更多的是代碼的穩定性和擴展性考慮。

         以上是在實際開發中需要面對的問題,筆者在最近的博文中,也在考慮這個異常到底需要怎么去寫,以及異常到底需要怎么去理解,在博文中,也有不少的園友對異常的寫法和處理提出了自己的意見,在這里我就寫一下自己的一些理解,可能寫的比較淺顯和粗略,但是只當是一個引子,可以引出大佬們來談談自己的實際項目經驗。希望對大家有一個幫助,也歡迎大家提出自己的想法和意見,分享自己的知識和見解。

        一.DotNET異常的概述:

        談到異常,我們就需要知道什么叫做異常,萬事萬物如果我們想去學習,就應該知道我們要學習的東西是什么,這樣在心里也好有一個大概的認知。異常是指成員沒有完成它的名稱宣稱可以完成的行動。在.NET中,構造器、獲取和設置屬性、添加和刪除事件、調用操作符重載和調用轉換操作符等等都沒有辦法返回錯誤代碼,但是在這些構造中又需要報告錯誤,那就必須提供異常處理機制。

        在異常的處理中,我們經常使用到的三個塊分別是:try塊;catch塊;finally塊。這三個塊可以一起使用,也可以不寫catch塊使用,異常處理塊可以嵌套使用,具體的方法在下面會介紹到。

        在異常的處理機制中,一般有三種選擇:重新拋出相同的異常,向調用棧高一層的代碼通知該異常的發生;拋出一個不同的異常,想調用棧高一層代碼提供更豐富的異常信息;讓線程從catch塊的底部退出。  

        有關異常的處理方式,有一些指導性的建議。

        1.恰當的使用finally塊:

        finally塊可以保證不管線程拋出什么類型的異常都可以被執行,finall塊一般用來做清理那些已經成功啟動的操作,然后再返回調用者或者finally塊之后的代碼。

        2.異常捕捉需適當:

        為什么要適當的捕捉異常呢?如下代碼,因為我們不能什么異常都去捕捉,在捕獲異常后,我們需要去處理這些異常,如果我們將所有的異常都捕捉后,但是沒有預見會發生的異常,我們就沒有辦法去處理這些異常。

        如果應用程序代碼拋出一個異常,應用程序的另一端則可能預期要捕捉這個異常,因此不能寫成一個”大小通吃“的異常塊,應該允許該異常在調用棧中向上移動,讓應用程序代碼針對性地處理這個異常。

        在catch塊中,可以使用System.Exception捕捉異常,但是最好在catch塊末尾重新拋出異常。至于原因在后面會講解到。

        try
         {
         var hkml = GetRegistryKey(rootKey);
         var subkey = hkml.CreateSubKey(subKey);
         if (subkey != null && keyName != string.Empty)
         subkey.SetValue(keyName, keyValue, RegistryValueKind.String);
         }
         catch (Exception ex)
         {
         Log4Helper.Error("創建注冊表錯誤" + ex);
         throw new Exception(ex.Message,ex);
         }

        3.從異常中恢復:

        我們在捕獲異常后,可以針對性的寫一些異常恢復的代碼,可以讓程序繼續運行。在捕獲異常時,需要捕獲具體的異常,充分的掌握在什么情況下會拋出異常,并知道從捕獲的異常類型派生出了那些類型。除非在catch塊的末尾重新拋出異常,否則不要處理或捕獲System.Exception異常。

        4.維持狀態:

        一般情況下,我們完成一個操作或者一個方法時,需要調用幾個方法組合完成,在執行的過程中會出現前面幾個方法完成,后面的方法發生異常。發生不可恢復的異常時回滾部分完成的操作,因為我們需要恢復信息,所有我們在捕獲異常時,需要捕獲所有的異常信息。

        5.隱藏實現細節來維持契約:

        有時可能需要捕捉一個異常并重新拋出一個不同的異常,這樣可以維系方法的契約,拋出的心異常類型地應該是一個具體的異常。看如下代碼:

        FileStream fs = null;
         try
         {
         fs = FileStream();
         
         }
         catch (FileNotFoundException e)
         {
                  //拋出一個不同的異常,將異常信息包含在其中,并將原來的異常設置為內部異常
         throw new NameNotFoundException();
         }
         catch (IOException e)
         {
         
         //拋出一個不同的異常,將異常信息包含在其中,并將原來的異常設置為內部異常
         throw new NameNotFoundException(); 
         } 
         finally 
         {
         if (fs != null) 
         { 
         fs.close(); 
         } 
         }

        以上的代碼只是在說明一種處理方式。應該讓拋出的所有異常都沿著方法的調用棧向上傳遞,而不是把他們”吞噬“了之后拋出一個新的異常。如果一個類型構造器拋出一個異常,而且該異常未在類型構造器方法中捕獲,CLR就會在內部捕獲該異常,并改為拋出一個新的TypeInitialztionException。

        二.DotNET異常的常用處理機制:

        在代碼發生異常后,我們需要去處理這個異常,如果一個異常沒有得到及時的處理,CLR會終止進程。在異常的處理中,我們可以在一個線程捕獲異常,在另一個線程中重新拋出異常。異常拋出時,CLR會在調用棧中向上查找與拋出的異常類型匹配的catch塊。如果沒有任何catch塊匹配拋出的異常類型,就發生一個未處理異常。CLR檢測到進程中的任何線程有一個位處理異常,都會終止進程。

        1.異常處理塊:

        (1).try塊:包含代碼通常需要執行一些通用的資源清理操作,或者需要從異常中恢復,或者兩者都需要。try塊還可以包含也許會拋出異常的代碼。一個try塊至少有一個關聯的catch塊或finall塊。      

        (2).catch塊:包含的是響應一個異常需要執行的代碼。catch關鍵字后的圓括號中的表達式是捕獲類型。捕獲類型從System.Exception或者其派生類指定。CLR自上而下搜素一個匹配的catch塊,所以應該教具體的異常放在頂部。一旦CLR找到一個具有匹配捕獲類型的catch塊,就會執行內層所有finally塊中的代碼,”內層finally“是指拋出異常的tey塊開始,到匹配異常的catch塊之間的所有finally塊。

        使用System.Exception捕捉異常后,可以采用在catch塊的末尾重新拋出異常,因為如果我們在捕獲Exception異常后,沒有及時的處理或者終止程序,這一異常可能對程序造成很大的安全隱患,Exception類是所有異常的基類,可以捕獲程序中所有的異常,如果出現較大的異常,我們沒有及時的處理,造成的問題是巨大的。

        (3).finally塊:包含的代碼是保證會執行的代碼。finally塊的所有代碼執行完畢后,線程退出finally塊,執行緊跟在finally塊之后的語句。如果不存在finally塊,線程將從最后一個catch塊之后的語句開始執行。

        備注:異常塊可以組合和嵌套,對于三個異常塊的樣例,在這里就不做介紹,異常的嵌套可以防止在處理異常的時候再次出現未處理的異常,以上這些就不再贅述。

        2.異常處理實例:

        (1).異常處理擴展方法:

         /// <summary>
         /// 格式化異常消息
         /// </summary>
         /// <param name="e">異常對象</param>
         /// <param name="isHideStackTrace">是否隱藏異常規模信息</param>
         /// <returns>格式化后的異常信息字符串</returns>
         public static string FormatMessage(this Exception e, bool isHideStackTrace = false)
         {
         var sb = new StringBuilder();
         var count = 0;
         var appString = string.Empty;
         while (e != null)
         {
         if (count > 0)
         {
         appString += " ";
         }
         sb.AppendLine(string.Format("{0}異常消息:{1}", appString, e.Message));
         sb.AppendLine(string.Format("{0}異常類型:{1}", appString, e.GetType().FullName));
         sb.AppendLine(string.Format("{0}異常方法:{1}", appString, (e.TargetSite == null ? null : e.TargetSite.Name)));
         sb.AppendLine(string.Format("{0}異常源:{1}", appString, e.Source));
         if (!isHideStackTrace && e.StackTrace != null)
         {
         sb.AppendLine(string.Format("{0}異常堆棧:{1}", appString, e.StackTrace));
         }
         if (e.InnerException != null)
         {
         sb.AppendLine(string.Format("{0}內部異常:", appString));
         count++;
         }
         e = e.InnerException;
         }
         return sb.ToString();
         }

        (2).驗證異常:

         /// <summary>
         /// 檢查字符串是空的或空的,并拋出一個異常
         /// </summary>
         /// <param name="val">值測試</param>
         /// <param name="paramName">參數檢查名稱</param>
         public static void CheckNullOrEmpty(string val, string paramName)
         {
         if (string.IsNullOrEmpty(val))
         throw new ArgumentNullException(paramName, "Value can't be null or empty");
         }
         /// <summary>
         /// 請檢查參數不是空的或空的,并拋出異常
         /// </summary>
         /// <param name="param">檢查值</param>
         /// <param name="paramName">參數名稱</param>
         public static void CheckNullParam(string param, string paramName)
         {
         if (string.IsNullOrEmpty(param))
         throw new ArgumentNullException(paramName, paramName + " can't be neither null nor empty");
         }
         /// <summary>
         /// 檢查參數不是無效,并拋出一個異常
         /// </summary>
         /// <param name="param">檢查值</param>
         /// <param name="paramName">參數名稱</param>
         public static void CheckNullParam(object param, string paramName)
         {
         if (param == null)
         throw new ArgumentNullException(paramName, paramName + " can't be null");
         }
         /// <summary>
         /// 請檢查參數1不同于參數2
         /// </summary>
         /// <param name="param1">值1測試</param>
         /// <param name="param1Name">name of value 1</param>
         /// <param name="param2">value 2 to test</param>
         /// <param name="param2Name">name of vlaue 2</param>
         public static void CheckDifferentsParams(object param1, string param1Name, object param2, string param2Name)
         {
         if (param1 == param2) {
         throw new ArgumentException(param1Name + " can't be the same as " + param2Name,
         param1Name + " and " + param2Name);
         }
         }
         /// <summary>
         /// 檢查一個整數值是正的(0或更大)
         /// </summary>
         /// <param name="val">整數測試</param>
         public static void PositiveValue(int val)
         {
         if (val < 0)
         throw new ArgumentException("The value must be greater than or equal to 0.");
         }
        

        (3).Try-Catch擴展操作:

        /// <summary>
         /// 對某對象執行指定功能與后續功能,并處理異常情況
         /// </summary>
         /// <typeparam name="T">對象類型</typeparam>
         /// <param name="source">值</param>
         /// <param name="action">要對值執行的主功能代碼</param>
         /// <param name="failureAction">catch中的功能代碼</param>
         /// <param name="successAction">主功能代碼成功后執行的功能代碼</param>
         /// <returns>主功能代碼是否順利執行</returns>
         public static bool TryCatch<T>(this T source, Action<T> action, Action<Exception> failureAction,
         Action<T> successAction) where T : class
         {
         bool result;
         try
         {
         action(source);
         successAction(source);
         result = true;
         }
         catch (Exception obj)
         {
         failureAction(obj);
         result = false;
         }
         return result;
         }
         /// <summary>
         /// 對某對象執行指定功能,并處理異常情況
         /// </summary>
         /// <typeparam name="T">對象類型</typeparam>
         /// <param name="source">值</param>
         /// <param name="action">要對值執行的主功能代碼</param>
         /// <param name="failureAction">catch中的功能代碼</param>
         /// <returns>主功能代碼是否順利執行</returns>
         public static bool TryCatch<T>(this T source, Action<T> action, Action<Exception> failureAction) where T : class
         {
         return source.TryCatch(action,
         failureAction,
         obj => { });
         }
         /// <summary>
         /// 對某對象執行指定功能,并處理異常情況與返回值
         /// </summary>
         /// <typeparam name="T">對象類型</typeparam>
         /// <typeparam name="TResult">返回值類型</typeparam>
         /// <param name="source">值</param>
         /// <param name="func">要對值執行的主功能代碼</param>
         /// <param name="failureAction">catch中的功能代碼</param>
         /// <param name="successAction">主功能代碼成功后執行的功能代碼</param>
         /// <returns>功能代碼的返回值,如果出現異常,則返回對象類型的默認值</returns>
         public static TResult TryCatch<T, TResult>(this T source, Func<T, TResult> func, Action<Exception> failureAction,
         Action<T> successAction)
         where T : class
         {
         TResult result;
         try
         {
         var u = func(source);
         successAction(source);
         result = u;
         }
         catch (Exception obj)
         {
         failureAction(obj);
         result = default(TResult);
         }
         return result;
         }
         /// <summary>
         /// 對某對象執行指定功能,并處理異常情況與返回值
         /// </summary>
         /// <typeparam name="T">對象類型</typeparam>
         /// <typeparam name="TResult">返回值類型</typeparam>
         /// <param name="source">值</param>
         /// <param name="func">要對值執行的主功能代碼</param>
         /// <param name="failureAction">catch中的功能代碼</param>
         /// <returns>功能代碼的返回值,如果出現異常,則返回對象類型的默認值</returns>
         public static TResult TryCatch<T, TResult>(this T source, Func<T, TResult> func, Action<Exception> failureAction)
         where T : class
         {
         return source.TryCatch(func,
         failureAction,
         obj => { });
         }
        

        本文沒有具體介紹try,catch,finally的使用,而是給出一些比較通用的方法,主要是一般的開發者對于三個塊的使用都有一個認識,就不再做重復的介紹。

        三.DotNET的Exception類分析:

        CLR允許異常拋出任何類型的實例,這里我們介紹一個System.Exception類:

        1.Message屬性:指出拋出異常的原因。

         [__DynamicallyInvokable]
        public virtual string Message
        {
         [__DynamicallyInvokable]
         get
         {
         if (this._message != null)
         {
         return this._message;
         }
         if (this._className == null)
         {
         this._className = this.GetClassName();
         }
         return Environment.GetRuntimeResourceString("Exception_WasThrown", new object[] { this._className });
         }
        }

        由以上的代碼可以看出,Message只具有get屬性,所以message是只讀屬性。GetClassName()獲取異常的類。GetRuntimeResourceString()獲取運行時資源字符串。

        2.StackTrace屬性:包含拋出異常之前調用過的所有方法的名稱和簽名。

         public static string StackTrace
        {
         [SecuritySafeCritical]
         get
         {
         new EnvironmentPermission(PermissionState.Unrestricted).Demand();
         return GetStackTrace(null, true);
         }
        }

        EnvironmentPermission()用于環境限制,PermissionState.Unrestricted設置權限狀態,GetStackTrace()獲取堆棧跟蹤,具體看一下GetStackTrace()的代碼。

         internal static string GetStackTrace(Exception e, bool needFileInfo)
        {
         StackTrace trace;
         if (e == null)
         {
         trace = new StackTrace(needFileInfo);
         }
         else
         {
         trace = new StackTrace(e, needFileInfo);
         }
         return trace.ToString(StackTrace.TraceFormat.Normal);
        }
        public StackTrace(Exception e, bool fNeedFileInfo)
        {
         if (e == null)
         {
         throw new ArgumentNullException("e");
         }
         this.m_iNumOfFrames = 0;
         this.m_iMethodsToSkip = 0;
         this.CaptureStackTrace(0, fNeedFileInfo, null, e);
        }

         以上是獲取堆棧跟蹤方法的具體實現,此方法主要用戶調試的時候。

        3.GetBaseException()獲取基礎異常信息方法。

         [__DynamicallyInvokable]
        public virtual Exception GetBaseException()
        {
         Exception innerException = this.InnerException;
         Exception exception2 = this;
         while (innerException != null)
         {
         exception2 = innerException;
         innerException = innerException.InnerException;
         }
         return exception2;
        }

        InnerException屬性是內在異常,這是一個虛方法,在這里被重寫。具體看一下InnerException屬性。

        [__DynamicallyInvokable]
        public Exception InnerException
        {
         [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
         get
         {
         return this._innerException;
         }
        }

        4.ToString()將異常信息格式化。

        private string ToString(bool needFileLineInfo, bool needMessage)
        {
         string className;
         string str = needMessage ? this.Message : null;
         if ((str == null) || (str.Length <= 0))
         {
         className = this.GetClassName();
         }
         else
         {
         className = this.GetClassName() + ": " + str;
         }
         if (this._innerException != null)
         {
         className = className + " ---> " + this._innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine + " " + Environment.GetRuntimeResourceString("Exception_EndOfInnerExceptionStack");
         }
         string stackTrace = this.GetStackTrace(needFileLineInfo);
         if (stackTrace != null)
         {
         className = className + Environment.NewLine + stackTrace;
         }
         return className;
        }

        在此方法中,將獲取的異常信息進行格式化為字符串,this.GetClassName() 獲取異常類的相關信息。

        以上我們注意到[__DynamicallyInvokable]定制屬性,我們看一下具體的實現代碼:

        [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
        public __DynamicallyInvokableAttribute()
        {
        }

        以上我們主要注釋部分,”圖像邊界“這個屬性的相關信息,請參見《CLR via C#》,這里就不做具體的介紹。

        四.總結:

        以上在對異常的介紹中,主要介紹了CLR的異常處理機制,一些較為通用的異常代碼,以及對Exception類的介紹。在實際的項目中,我們一般不要將異常直接拋出給客戶,我們在編寫程序時,已經考慮程序的容錯性,在程序捕獲到異常后,盡量去恢復程序,或者將異常信息寫入日志,讓程序進入錯誤頁。如果出現比較嚴重的異常,最后將異常拋出,終止程序。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        詳談.NET的異常處理

        詳談.NET的異常處理:年關將至,對于大部分程序員來說,馬上就可以閑下來一段時間了,然而在這個閑暇的時間里,唯有爭論哪門語言更好可以消磨時光,估計最近會有很多關于java與.net的博文出現,我表示要作為一個吃瓜群眾,靜靜的看著大佬們發表心情。 以上的廢話說的夠多了,這里
        推薦度:
        標簽: 處理 錯誤 異常
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 凹凸精品视频分类国产品免费| 小草在线看片免费人成视久网| 亚洲毛片无码专区亚洲乱| 巨胸喷奶水视频www免费视频| 亚洲国产香蕉人人爽成AV片久久| 粉色视频免费入口| 免费成人在线观看| 亚洲精品动漫在线| 亚洲成年人免费网站| 亚洲欧洲精品在线| 成人毛片免费观看| 亚洲aⅴ无码专区在线观看| 国产v片免费播放| 一区二区视频免费观看| 91青青国产在线观看免费| 亚洲va在线va天堂va四虎| 精品无码国产污污污免费网站| 亚洲欧洲日产韩国在线| 成人午夜性A级毛片免费| 亚洲av永久无码天堂网| 亚洲精品无码专区久久同性男| jizz免费观看| 日产乱码一卡二卡三免费| 亚洲AV无码成人网站在线观看| 一级毛片直播亚洲| 亚洲爆乳AAA无码专区| 又粗又大又猛又爽免费视频| 一级做a爰性色毛片免费| 亚洲Av无码精品色午夜| 日韩免费精品视频| 色多多免费视频观看区一区| 亚洲成a人片77777kkkk| 国产精彩免费视频| 免费一级毛片在线播放视频免费观看永久| 国产AⅤ无码专区亚洲AV| 69xx免费观看视频| 一区二区视频免费观看| 亚洲一级毛片在线播放| 亚洲高清偷拍一区二区三区| 免费A级毛片无码专区| 另类小说亚洲色图|