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 можно использовать без аргументов для перехвата любого типа исключения, такой подход не рекомендуется.В общем случае следует перехватывать только те исключения, устранение причин которых известно.Поэтому следует всегда задавать аргумент объекта, производного от System.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<TResult>.Выражение 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#.

См. также

Задачи

Практическое руководство. Явное создание исключения

Ссылки

Ключевые слова C#

попробуйте, перехватывайте и вызывайте выписки (C++)

Операторы обработки исключений (Справочник по C#)

throw (Справочник по C#)

try-finally (Справочник по C#)

Основные понятия

Руководство по программированию на C#

Другие ресурсы

Справочник по C#