舉個例子:
static void Main(string[] args)
{
FileStream sw = null;
try
{
? sw = new FileStream(@"C:\test\test.txt", FileMode.Open, FileAccess.ReadWrite)
? sw.Write(new byte[1]);
}
catch (DirectoryNotFoundException ex)
{
//文件目錄沒有找到異常
Console.WriteLine(ex);
}
catch (FileNotFoundException ex)
{
//文件沒有找到異常
Console.WriteLine(ex);
}
catch (IOException ex)
{
//io操作異常
Console.WriteLine(ex);
}
finally
{
sw?.Flush();
sw?.Close();
}
}
沒有找到找到相應的catch,那么會一步一步往下找。
首先是查看DirectoryNotFoundException ,然后是FileNotFoundException,只要是io操作出現(xiàn)問題都會是IOException。
那么我該如何知道DirectoryNotFoundException、FileNotFoundException、IOException他們的關系呢?
這時候就需要看圖了,圖不大,可以記下來。
如圖:
上面這些是常用的,可以說是必會的吧,下面介紹一下他們的作用。
異常 詳細
ArgumentException 方法參數(shù)異常
ArgumentNullException 參數(shù)為空異常
ArgumentOutOfRangeException 索引小于零或超出數(shù)組邊界時,嘗試對數(shù)組編制索引時引發(fā)
ArithmeticException 算術運算期間出現(xiàn)的異常的基類,例如 DivideByZeroException 和 OverflowException。
OverflowException 當在檢查的上下文中執(zhí)行的算術、強制轉(zhuǎn)換或轉(zhuǎn)換運算導致溢出時引發(fā)的異常
StackOverflowException 執(zhí)行堆棧由于有過多掛起的方法調(diào)用而用盡時引發(fā);通常表示非常深的遞歸或無限遞歸。
IOException 發(fā)生I/O錯誤時引發(fā)的異常。
FileLoadException 找到托管程序集但不能加載時引發(fā)的異常
FileNotFoundException 文件沒有找到
EndOfSteamExcetion 讀操作試圖超出流的末尾時引發(fā)的異常。
DriveNotFoundException 當嘗試訪問的驅(qū)動器或共享不可用時引發(fā)的異常。
ApplicationException 用作應用程序定義的異常的基類
TargetInvocationException 由通過反射調(diào)用的方法引發(fā)的異常
CompositionException 表示在 CompositionContainer 對象中進行組合期間發(fā)生一個或多個錯誤時引發(fā)的異常。
ChangeRejectedException 一個指示部件在組合期間是否已遭拒絕的異常。
有些異常是我們寫代碼不應該去產(chǎn)生異常的,比如說ApplicationException作為基類的異常,如果出現(xiàn)這些異常一般是我們代碼寫的有問題,
而不是我們的主觀因素。應從 Exception 類(而不是 ApplicationException 類)派生自定義異常。 不應在代碼中引發(fā) ApplicationException 異常,除非你
打算重新引發(fā)原始異常,否則不應捕獲 ApplicationException 異常。 這里舉個例子:TargetInvocationException的基類是ApplicationException,這個是
由通過反射調(diào)用的方法引發(fā)的異常。如果產(chǎn)生這個問題,可以想象是我們反射使用的有問題。同樣如果我們?nèi)懛瓷涞某绦颍覀儾粦撊atch這個,而是讓他直接
報錯,表示代碼就不應該這么寫,出錯然后去解決。
好吧,回到原問題上,假如沒有找到兼容性的catch塊那么會怎么樣呢?
那么實驗一下吧。
實驗如下:
會拋出異常的,所以我們寫代碼的時候需要確保最后一個一定能捕獲到異常的,如果sw.Write(new byte[1]);出現(xiàn)錯誤那么非托管資源就沒有釋放。
那么如何萬一我們沒有捕獲到異常也能是否非托管資源呢?使用using。
static void Main(string[] args)
{
try
{
using (var sw = new FileStream(@"C:\test\test.txt", FileMode.Open, FileAccess.ReadWrite))
{
sw.Write(new byte[1]);
}
}
catch (DirectoryNotFoundException ex)
{
//文件目錄沒有找到異常
Console.WriteLine(ex);
}
finally
{
}
}
這樣寫無論是否異常,那么都會釋放非托管資源。這個是可以實驗的,我把我的實驗貼一下。
上面的說明已經(jīng)被關閉了,我們再次關閉的時候?qū)a(chǎn)生異常。這個using可以看下IL,就清楚其中的原理。
異常過濾器
異常過濾器是c#的東西,這里只是做簡單的介紹,后面異常代碼優(yōu)化章節(jié)中會重點介紹。
public static bool ConsoleLogException(Exception e)
{
var oldColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Error:{0}",e);
Console.ForegroundColor = oldColor;
return false;
}
static void Main(string[] args)
{
int i = 10;
try
{
throw new TimeoutException("time out");
}
catch (Exception e) when(ConsoleLogException(e))
{
}
catch (TimeoutException e) when (i == 10)
{
}
finally
{
Console.ReadKey();
}
}
輸出結(jié)果:
上面說明一個問題,無論catch是否匹配,when都會執(zhí)行。
同樣來做一個實驗,判斷when 如果不匹配也就是沒有catch塊執(zhí)行那么會怎么樣?
static void Main(string[] args)
{
int i = 10;
try
{
throw new TimeoutException("time out");
}
catch (Exception e) when(ConsoleLogException(e))
{
}
catch (TimeoutException e) when (i == 9)
{
Console.WriteLine("enter timeoutexception");
}
finally
{
Console.ReadKey();
}
}
結(jié)果:
重新拋出異常
為什么要重新拋出異常呢?
static int GetValueFromArray(int[] array, int index)
{
try
{
return array[index];
}
catch (System.IndexOutOfRangeException ex)
{
System.ArgumentException argEx = new System.ArgumentException("Index is out of range", "index", ex);
throw argEx;
}
}
本來是要拋出IndexOutOfRangeException 改為了ArgumentException 這是為什么呢?
原因如下:用戶要調(diào)用的是我們的方法GetValueFromArray,傳入的是參數(shù),方法沒有越界這么一說,而不是一個數(shù)組,所以我們要爭對我們的目的來確定我們拋出的異常。
用戶自定義異常
自定義異常水比較深,在此只做一個簡單的介紹,單獨一節(jié)補齊。
class CostumExcetion:Exception
{
public CostumExcetion(string message) : base(message)
{
}
}
調(diào)用如下:
static void Main(string[] args)
{
int i = 10;
try
{
throw new CostumExcetion("自定義異常");
}
catch (Exception e) when(ConsoleLogException(e))
{
}
catch (CostumExcetion e) when (i == 10)
{
Console.WriteLine(e.Message);
}
finally
{
Console.ReadKey();
}
}
調(diào)用者信息
現(xiàn)在又一個需要,知道try中出現(xiàn)錯誤,但是我需要知道是那一會出現(xiàn)錯誤,這個怎么破呢?
也就是說我們希望定位到行級,那么我們就需要調(diào)用者信息了。
在異常中,我們又很多方法調(diào)用一個方法,然后在這個方法中出現(xiàn)問題,我們需要知道是怎么報錯的,到底是哪個函數(shù)調(diào)用報錯的,這時候我們需要使用查詢到調(diào)用者信息。
舉個例子:
public class CallerInformationHelper
{
public void Log([CallerLineNumber]int line = -1, [CallerFilePath] string path = null, [CallerMemberName]string name = null)
{
Console.WriteLine((line<0)?"no line":"Line"+line);
Console.WriteLine((path==null)?"No file path":path);
Console.WriteLine((name==null)?"No Member name":name);
Console.WriteLine();
}
}
調(diào)用:
CallerInformationHelper helper = new CallerInformationHelper();
helper.Log();
深圳網(wǎng)站建設www.sz886.com