try-catch (C# 參考)
try-catch 陳述式是由其後跟隨一個或多個 catch 子句的 try 區塊組成,以指定不同例外狀況的處理常式。
備註
擲回例外狀況時,Common Language Runtime (CLR) 會尋找處理此例外狀況的 catch 陳述式。 如果目前執行的方法未包含這種 catch 區塊,CLR 會檢查呼叫目前方法的方法,一直向上檢查至呼叫堆疊。 如果找不到 catch 區塊,CLR 就會顯示未處理的例外狀況訊息以告知使用者,並停止執行程式。
try 區塊中含有可能會導致例外狀況並受到嚴密監控的程式碼。 執行區塊直到擲回例外狀況或已成功完成。 例如,以下轉換 null 物件的嘗試會引發 NullReferenceException 例外狀況:
object o2 = null;
try
{
int i2 = (int)o2; // Error
}
雖然 catch 子句可在無引數的情況下使用來呼叫任何類型的例外狀況,但不建議這種用法。 一般來說,您應該只攔截那些您知道如何復原的例外狀況。 因此,您一定要指定衍生自 Exception 的物件引數,例如:
catch (InvalidCastException e)
{
}
在相同的 try-catch 陳述式中,有可能使用一個以上特定 catch 子句。 此時由於 catch 子句是依照順序進行檢查,因此 catch 子句的順序就非常重要。 在較不特定的例外狀況之前攔截較特定的例外狀況。 如果因 catch 區塊順序而導致永遠無法執行到後面的區塊,編譯器會產生錯誤。
throw 陳述式可以用於 catch 區塊中,以重新擲回 catch 陳述式所攔截的例外狀況。 下列範例會從 IOException 例外狀況中擷取來源資訊,然後將例外狀況擲回到父方法。
catch (FileNotFoundException e)
{
// FileNotFoundExceptions are handled here.
}
catch (IOException e)
{
// Extract some information from this exception, and then
// throw it to the parent method.
if (e.Source != null)
Console.WriteLine("IOException source: {0}", e.Source);
throw;
}
您可以攔截一個例外狀況,並擲回不同的例外狀況。 當您這樣做時,請指定您當做內部例外狀況攔截到的例外狀況,如下列範例中所示。
catch (InvalidCastException e)
{
// Perform some action here, and then throw a new exception.
throw new YourCustomException("Put your error message here.", e);
}
當指定的條件為 true 時,您也可以重新擲回例外狀況,如下列範例中所示。
catch (InvalidCastException e)
{
if (e.Data == null)
{
throw;
}
else
{
// Take some action.
}
}
從 try 區塊內部,指初始化在此宣告的變數。 否則,區塊執行完成前可能會發生例外狀況。 例如下列程式碼範例中的 n 變數就是在 try 區塊中進行初始化。 Write(n) 陳述式中,如果嘗試在 try 區塊外面使用這個變數,會產生以下編譯器錯誤。
static void Main()
{
int n;
try
{
// Do not initialize this variable here.
n = 123;
}
catch
{
}
// Error: Use of unassigned local variable 'n'.
Console.Write(n);
}
如需 catch 的詳細資訊,請參閱 try-catch-finally。
在非同步方法的例外狀況。
非同步方法由 非同步 修飾詞指令和通常包含一個或多個等候運算式或陳述式。 表示等候應用 等候 運算子對 Task 或 Task。 await 表示在 catch 區塊或 finally 區塊不會發生。
當控制項到達非同步方法的 await ,方法中的進度暫止,直到等候的工作完成。 當工作完成時,則會從方法可以復原。 如需詳細資訊,請參閱使用 Async 和 Await 設計非同步程式 (C# 和 Visual Basic)與非同步程式中的控制流程 (C# 和 Visual Basic)。
await 套用的完整工作可能是處於錯誤狀態由於傳回工作的方法的 Unmanaged 例外狀況。 等候工作擲回例外狀況。 工作已取消狀態也結果,如果傳回已取消的非同步處理序。 等候已取消的工作擲回 OperationCanceledException。 如需如何取消非同步處理序的詳細資訊,請參閱 微調非同步應用程式 (C# 和 Visual Basic)。
攔截例外狀況,在等候 try 區塊的工作並攔截在關聯的 catch 區塊中的例外狀況。 如需範例,請參閱<範例>一節。
因為多個例外狀況在等候的非同步方法,產生了工作可以處於錯誤狀態。 例如,工作可能是呼叫的結果指派給 Task.WhenAll。 當您等候這類工作時,,只有其中一個例外狀況和您無法預測哪個例外狀況會攔截它。 如需範例,請參閱<範例>一節。
範例
在下列範例中,try 區塊包含 ProcessString 方法的呼叫,這個呼叫可能會造成例外狀況。 catch 子句包含只會在畫面上顯示訊息的例外狀況處理常式 (Exception Handler)。 從 MyMethod 內部呼叫 throw 陳述式時,系統會尋找 catch 陳述式並且顯示 Exception caught 訊息。
class TryFinallyTest
{
static void ProcessString(string s)
{
if (s == null)
{
throw new ArgumentNullException();
}
}
static void Main()
{
string s = null; // For demonstration purposes.
try
{
ProcessString(s);
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
}
}
/*
Output:
System.ArgumentNullException: Value cannot be null.
at TryFinallyTest.Main() Exception caught.
* */
在下列範例中,使用兩個 catch 區塊,因此,最特定的例外狀況,先),會攔截。
若要攔截最不特定的例外狀況,您可以用下列陳述式取代 ProcessString 的 Throw 陳述式: throw new Exception()。
如果您在這個範例會先最不特定的 catch 區塊,會出現下列錯誤訊息: A previous catch clause already catches all exceptions of this or a super type ('System.Exception')。
class ThrowTest3
{
static void ProcessString(string s)
{
if (s == null)
{
throw new ArgumentNullException();
}
}
static void Main()
{
try
{
string s = null;
ProcessString(s);
}
// Most specific:
catch (ArgumentNullException e)
{
Console.WriteLine("{0} First exception caught.", e);
}
// Least specific:
catch (Exception e)
{
Console.WriteLine("{0} Second exception caught.", e);
}
}
}
/*
Output:
System.ArgumentNullException: Value cannot be null.
at Test.ThrowTest3.ProcessString(String s) ... First exception caught.
*/
下列範例說明例外狀況處理的非同步方法。 若要攔截非同步工作擲回,則在 try 區塊放置 await 表示的例外狀況,並攔截在 catch 區塊中的例外狀況。
取消註解在示範例外狀況處理的範例中的 throw new Exception 線條。 工作的 IsFaulted 屬性設定為, True工作的 Exception.InnerException 屬性設為例外狀況,,而且已在 catch 區塊攔截。
取消註解中發生的事情的 throw new OperationCancelledException 行,當您 cancelan 非同步處理序。 工作的 IsCanceled 屬性設定為, true,而且已在 catch 區塊攔截。 在某些條件下這並不適用於這個範例,工作的 IsFaulted 屬性設定為 true ,並 IsCanceled 設為 false。
public async Task DoSomethingAsync()
{
Task<string> theTask = DelayAsync();
try
{
string result = await theTask;
Debug.WriteLine("Result: " + result);
}
catch (Exception ex)
{
Debug.WriteLine("Exception Message: " + ex.Message);
}
Debug.WriteLine("Task IsCanceled: " + theTask.IsCanceled);
Debug.WriteLine("Task IsFaulted: " + theTask.IsFaulted);
if (theTask.Exception != null)
{
Debug.WriteLine("Task Exception Message: "
+ theTask.Exception.Message);
Debug.WriteLine("Task Inner Exception Message: "
+ theTask.Exception.InnerException.Message);
}
}
private async Task<string> DelayAsync()
{
await Task.Delay(100);
// Uncomment each of the following lines to
// demonstrate exception handling.
//throw new OperationCanceledException("canceled");
//throw new Exception("Something happened.");
return "Done";
}
// Output when no exception is thrown in the awaited method:
// Result: Done
// Task IsCanceled: False
// Task IsFaulted: False
// Output when an Exception is thrown in the awaited method:
// Exception Message: Something happened.
// Task IsCanceled: False
// Task IsFaulted: True
// Task Exception Message: One or more errors occurred.
// Task Inner Exception Message: Something happened.
// Output when a OperationCanceledException or TaskCanceledException
// is thrown in the awaited method:
// Exception Message: canceled
// Task IsCanceled: True
// Task IsFaulted: False
下列範例說明例外狀況處理多項工作可能會導致多個例外狀況的地方。 try 區塊 Task.WhenAll等候由對的呼叫傳回的工作。 工作完成,則 WhenAll 套用時的三項工作已完成。
三個原因工作中的每一個例外狀況。 catch 區塊傳遞例外狀況逐一查看,在工作 Exception.InnerExceptions 屬性中所 Task.WhenAll傳回。
public async Task DoMultipleAsync()
{
Task theTask1 = ExcAsync(info: "First Task");
Task theTask2 = ExcAsync(info: "Second Task");
Task theTask3 = ExcAsync(info: "Third Task");
Task allTasks = Task.WhenAll(theTask1, theTask2, theTask3);
try
{
await allTasks;
}
catch (Exception ex)
{
Debug.WriteLine("Exception: " + ex.Message);
Debug.WriteLine("Task IsFaulted: " + allTasks.IsFaulted);
foreach (var inEx in allTasks.Exception.InnerExceptions)
{
Debug.WriteLine("Task Inner Exception: " + inEx.Message);
}
}
}
private async Task ExcAsync(string info)
{
await Task.Delay(100);
throw new Exception("Error-" + info);
}
// Output:
// Exception: Error-First Task
// Task IsFaulted: True
// Task Inner Exception: Error-First Task
// Task Inner Exception: Error-Second Task
// Task Inner Exception: Error-Third Task
C# 語言規格
如需詳細資訊,請參閱<C# 語言規格>。語言規格是 C# 語法及用法的限定來源。