1. 程式人生 > >解析Exception和C#處理Exception的常用方法總結

解析Exception和C#處理Exception的常用方法總結

    異常處理四要素包括:一個表示異常詳細資訊的類型別;一個向呼叫者引發異常類例項的成員;呼叫者的一段呼叫異常成員的程式碼塊;呼叫者的一段處理將要發生異常的程式碼塊。異常類型別包括:基類:System.Exception;系統級異常:System.SystemException;應用程式級異常:System.ApplicationException。

   (一).在.NET中有如下的異常類:

     (1).由System.SystemException派生的異常型別:

System.AccessViolationException 在試圖讀寫受保護記憶體時引發的異常。
System.ArgumentException 在向方法提供的其中一個引數無效時引發的異常。
System.Collections.Generic.KeyNotFoundException 指定用於訪問集合中元素的鍵與集合中的任何鍵都不匹配時所引發的異常。
System.IndexOutOfRangeException 訪問陣列時,因元素索引超出陣列邊界而引發的異常。
System.InvalidCastException 因無效型別轉換或顯示轉換引發的異常。
System.InvalidOperationException 當方法呼叫對於物件的當前狀態無效時引發的異常。
System.InvalidProgramException 當程式包含無效Microsoft中間語言(MSIL)或元資料時引發的異常,這通常表示生成程式的編譯器中有bug。
System.IO.IOException 發生I/O錯誤時引發的異常。
System.NotImplementedException 在無法實現請求的方法或操作時引發的異常。
System.NullReferenceException 嘗試對空物件引用進行操作時引發的異常。
System.OutOfMemoryException 沒有足夠的記憶體繼續執行程式時引發的異常。
System.StackOverflowException 掛起的方法呼叫過多而導致執行堆疊溢位時引發的異常。

   (2).由System.ArgumentException派生的異常型別:

System.ArgumentNullException 當將空引用傳遞給不接受它作為有效引數的方法時引發的異常。
System.ArgumentOutOfRangeException 當引數值超出呼叫的方法所定義的允許取值範圍時引發的異常。

  (3).由System.ArithmeticException派生的異常型別:

System.DivideByZeroException 試圖用零除整數值或十進位制數值時引發的異常。
System.NotFiniteNumberException 當浮點值為正無窮大、負無窮大或非數字(NaN)時引發的異常。
System.OverflowException 在選中的上下文中所進行的算數運算、型別轉換或轉換操作導致溢位時引發的異常。

 (4).由System.IOException派生的異常型別:

System.IO.DirectoryNotFoundException 當找不到檔案或目錄的一部分時所引發的異常。
System.IO.DriveNotFoundException 當嘗試訪問的驅動器或共享不可用時引發的異常。
System.IO.EndOfStreamException 讀操作試圖超出流的末尾時引發的異常。
System.IO.FileLoadException 當找到託管程式卻不能載入它時引發的異常。
System.IO.FileNotFoundException 試圖訪問磁碟上不存在的檔案失敗時引發的異常。
System.IO.PathTooLongException 當路徑名或檔名超過系統定義的最大長度時引發的異常。

 (5).其他常用異常型別:     

ArrayTypeMismatchException 試圖在陣列中儲存錯誤型別的物件。
BadImageFormatException 圖形的格式錯誤。
DivideByZeroException 除零異常。
DllNotFoundException 找不到引用的dll。
FormatException 引數格式錯誤。
MethodAccessException 試圖訪問私有或者受保護的方法。
MissingMemberException 訪問一個無效版本的dll。
NotSupportedException 呼叫的方法在類中沒有實現。
PlatformNotSupportedException 平臺不支援某個特定屬性時丟擲該錯誤。

(二)..NET的異常處理方式:

      發生異常時,系統將搜尋可以處理該異常的最近的 catch 子句(根據該異常的執行時型別來確定)。首先,搜尋當前的方法以查詢一個詞法上包含著它的 try 語句,並按順序考察與該 try 語句相關聯的各個 catch 子句。如果上述操作失敗,則在呼叫了當前方法的方法中,搜尋在詞法上包含著當前方法呼叫程式碼位置的 try 語句。此搜尋將一直進行下去,直到找到可以處理當前異常的 catch 子句(該子句指定一個異常類,它與當前引發該異常的執行時型別屬於同一個類或是該執行時型別所屬類的一個基類)。注意,沒有指定異常類的 catch 子句可以處理任何異常。

   找到匹配的 catch 子句後,系統將把控制轉移到該 catch 子句的第一條語句。在 catch 子句的執行開始前,系統將首先按順序執行巢狀在捕捉到該異常的 try 語句裡面的所有 try 語句所對應的全部 finally 子句。

      (1).try塊:包含的程式碼通常需要執行一些通用的資源清理操作,或者需要從異常中恢復,或者兩者都需要。try塊還可以包含也許會丟擲異常的程式碼。

      (2).catch塊:包含的是響應一個異常需要執行的程式碼。如果沒有任何捕捉型別與丟擲的異常匹配,CLR會去呼叫棧的更高一層搜尋一個與異常匹配的捕捉型別。

      (3).finally塊:包含的程式碼是保證會執行的程式碼。finally塊所有程式碼執行完畢後,執行緒退出finally塊,執行緊跟在finally塊之後的語句。

(三).Exception的常用屬性的原始碼解析:

     (1).Message:包含輔助性文字說明,指出丟擲異常的原因。

複製程式碼
public virtual String Message {
               get {
                if (_message == null) {
                    if (_className==null) { 
                        _className = GetClassName();
                    } 
                    return Environment.GetRuntimeResourceString("Exception_WasThrown", _className); 

                } else { 
                    return _message;
                }
            }
        } 
複製程式碼

    (2).Data:對一個“鍵/值對”集合的引用。

複製程式碼
 public virtual IDictionary Data { 
            [System.Security.SecuritySafeCritical]  // auto-generated 
            get {
                if (_data == null) 
                    if (IsImmutableAgileException(this))
                        _data = new EmptyReadOnlyDictionaryInternal();
                    else
                        _data = new ListDictionaryInternal(); 

                return _data; 
            } 
        }
複製程式碼

   (3).Source:包含生成異常的程式集名稱。

複製程式碼
 public virtual String Source {
            #if FEATURE_CORECLR 
            [System.Security.SecurityCritical] // auto-generated
            #endif 
            get { 
                if (_source == null)
                { 
                    StackTrace st = new StackTrace(this,true);
                    if (st.FrameCount>0)
                    {
                        StackFrame sf = st.GetFrame(0); 
                        MethodBase method = sf.GetMethod();
 
                        Module module = method.Module; 

                        RuntimeModule rtModule = module as RuntimeModule; 

                        if (rtModule == null)
                        {
                            System.Reflection.Emit.ModuleBuilder moduleBuilder = module as System.Reflection.Emit.ModuleBuilder; 
                            if (moduleBuilder != null)
                                rtModule = moduleBuilder.InternalModule; 
                            else 
                                throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeReflectionObject"));
                        } 

                        _source = rtModule.GetRuntimeAssembly().GetSimpleName();
                    }
                } 

                return _source; 
            } 
            #if FEATURE_CORECLR
            [System.Security.SecurityCritical] // auto-generated 
            #endif
            set { _source = value; }
        }
複製程式碼

  (四).異常處理的常用方法:

    (1).提取異常及其內部異常堆疊跟蹤

複製程式碼
        /// <summary>
        /// 提取異常及其內部異常堆疊跟蹤
        /// </summary>
        /// <param name="exception">提取的例外</param>
        /// <param name="lastStackTrace">最後提取的堆疊跟蹤(對於遞迴), String.Empty or null</param>
        /// <param name="exCount">提取的堆疊數(對於遞迴)</param>
        /// <returns>Syste.String</returns>
        public static string ExtractAllStackTrace(this Exception exception, string lastStackTrace = null, int exCount = 1)
        {
            var ex = exception;
            const string entryFormat = "#{0}: {1}\r\n{2}";
            //修復最後一個堆疊跟蹤引數
            lastStackTrace = lastStackTrace ?? string.Empty;
            //新增異常的堆疊跟蹤
            lastStackTrace += string.Format(entryFormat, exCount, ex.Message, ex.StackTrace);
            if (exception.Data.Count > 0)
            {
                lastStackTrace += "\r\n    Data: ";
                foreach (var item in exception.Data)
                {
                    var entry = (DictionaryEntry)item;
                    lastStackTrace += string.Format("\r\n\t{0}: {1}", entry.Key, exception.Data[entry.Key]);
                }
            }
            //遞迴新增內部異常
            if ((ex = ex.InnerException) != null)
                return ex.ExtractAllStackTrace(string.Format("{0}\r\n\r\n", lastStackTrace), ++exCount);
            return lastStackTrace;
        }
複製程式碼

   (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");
        }
複製程式碼

  (3).檢查引數不是無效,並丟擲一個異常

複製程式碼
        /// <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");
        }
複製程式碼

   (4).請檢查引數1不同於引數2

複製程式碼
       /// <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);
            }
        }
複製程式碼

   (5).檢查一個整數值是正的(0或更大)

複製程式碼
        /// <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.");
        }
複製程式碼

    異常處理器(程式):對於程式中出現的異常,在C#中是使用一種被稱為“異常處理器(程式)”的錯誤捕獲機制來進行處理的, 你可以認為異常處理器(程式)就是發生錯誤時,能夠接受並處理錯誤的接受者和處理。