try-catch (Справочник по C#)
Оператор try-catch состоит из блока try, за которым следует одно или несколько предложений catch, в которых определяются обработчики для различных исключений.
Заметки
При возникновении исключения среда 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 таким образом, чтобы последующий блок был недостижимым, компилятор вызовет ошибку.
В блок catch можно включить оператор throw, чтобы заново создать исключение, перехваченное оператором 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);
}
Кроме того, можно повторно создать исключение, если заданное условие выполнено, как показано в следующем примере.
catch (InvalidCastException e)
{
if (e.Data == null)
{
throw;
}
else
{
// Take some action.
}
}
Из блока try следует инициализировать только те переменные, которые в нем объявлены. В противном случае исключение может произойти до того, как завершится выполнение блока. Например, в следующем примере кода переменная n инициализируется внутри блока try. Попытка использовать эту переменную вне блока try в операторе Write(n) приведет к ошибке компиляции.
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);
}
Дополнительные сведения о перехвате исключений см. в разделе try-catch-finally.
Исключения в Асинхронных методов
Метод асинхронного помечен модификатором async и обычно содержит один или несколько ожидает выражений или выписок. Выражение ожидания применяется оператор подождите к Task или Task. Выражение await не может произойти в блоке catch или блоке finally.
Если элемент управления достигает await в методе async, хода выполнения в методе приостанавливается до тех пор, пока подожданная задача не завершится. Если задача завершена, выполнение может возобновить в методе. Дополнительные сведения см. в разделах Асинхронное программирование с использованием ключевых слов Async и Await (C# и Visual Basic) и Поток управления в асинхронных программах (C# и Visual Basic).
Завершенная задача, к которой await применено может быть в состоянии сбоя из-за необработанного исключения в методе, который возвращает задачу. Ожидание задачи вызывает исключение. Задача также может выполнить поиск в отмененном состоянии, если асинхронный процесс, который возвращениям он отменяет. Ожидание отмененной задачи вызывает OperationCanceledException. Дополнительные сведения о том, как отменить процесс асинхронной см. в разделе Настройка асинхронного приложения (C# и Visual Basic).
Перехват исключения, подождать задачу в блоке try и перехватывать исключения в соответствующем блоке catch. Пример см. в подразделе "пример".
Задача может находиться в состоянии сбоя, так как несколько исключений в методе подожданном async. Например, задача может быть результатом вызова метода Task.WhenAll. Если ожидается такой задачи, перехватывается только одно из исключений, и невозможно предсказать, перехватывается исключение будет. Пример см. в подразделе "пример".
Пример
В следующем примере блок try содержит обращение к методу ProcessString, который может вызвать исключение. В предложении catch содержится обработчик исключения, который просто выводит на экран сообщение. Если оператор throw вызывается из метода MyMethod, система осуществляет поиск оператора 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.
* */
В следующем примере используются 2 блока catch и перехватывается самое конкретное исключение, который сначала.
Для перехвата наименьшее конкретное исключение, можно заменить оператор с ProcessString в следующей выпиской: 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.
*/
Следующий пример иллюстрирует обработку ошибок для асинхронных методов. Перехват исключения, штрихи задачи async, задать выражение await в блоке try и перехватывает исключения в блоке 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. Задача завершена, когда 3 задачи, к которой WhenAll применено завершения.
Каждая из задач 3 причин исключения. Блок 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#.
См. также
Задачи
Практическое руководство. Явное создание исключения
Ссылки
Операторы try, throw и catch (C++)
Операторы обработки исключений (Справочник по C#)
try-finally (Справочник по C#)
Основные понятия
Руководство по программированию на C#