Поиск…


замечания

Связанные с:

Ловля исключения

Код может и должен вызывать исключения в исключительных обстоятельствах. Примеры этого включают:

Вызывающий может обрабатывать эти исключения, «ловя их», и должен делать это только тогда, когда:

  • Он может фактически разрешить исключительные обстоятельства или восстановить надлежащим образом;
  • Это может обеспечить дополнительный контекст для исключения, которое было бы полезно, если бы исключение нужно было перебросить (повторные выбросы исключений улавливаются обработчиками исключений далее в стеке вызовов)

Следует отметить, что выбор не для того, чтобы поймать исключение, является вполне допустимым, если намерение заключается в том, чтобы его обрабатывали на более высоком уровне.

Захват исключения выполняется путем переноса потенциально метательного кода в блок try { ... } следующим образом и улавливания исключений, которые он может обрабатывать в блоке catch (ExceptionType) { ... } :

Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();

Stream fileStream;

try
{
    fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
    Console.WriteLine("File '{0}' could not be found.", filename);
}

Использование блока finally

finally { ... } блок try-finally или try-catch-finally всегда будет выполняться независимо от того, произошло ли исключение или нет (кроме случаев, когда StackOverflowException было выбрано или вызвано в Environment.FailFast() ).

Его можно использовать для бесплатной или очистки ресурсов, полученных в блоке try { ... } .

Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();

Stream fileStream = null;

try
{
    fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
    Console.WriteLine("File '{0}' could not be found.", filename);
}
finally
{
    if (fileStream != null)
    {
        fileStream.Dispose();
    }
}

Ловля и реорганизация пойманных исключений

Если вы хотите поймать исключение и что-то сделать, но вы не можете продолжить выполнение текущего блока кода из-за исключения, вы можете захотеть перебросить исключение в следующий обработчик исключений в стеке вызовов. Есть хорошие способы и плохие способы сделать это.

private static void AskTheUltimateQuestion()
{
    try
    {
        var x = 42;
        var y = x / (x - x); // will throw a DivideByZeroException

        // IMPORTANT NOTE: the error in following string format IS intentional
        // and exists to throw an exception to the FormatException catch, below
        Console.WriteLine("The secret to life, the universe, and everything is {1}", y); 
    }
    catch (DivideByZeroException)
    {
        // we do not need a reference to the exception
        Console.WriteLine("Dividing by zero would destroy the universe.");

        // do this to preserve the stack trace:
        throw;
    }
    catch (FormatException ex)
    {
        // only do this if you need to change the type of the Exception to be thrown 
        // and wrap the inner Exception

        // remember that the stack trace of the outer Exception will point to the
        // next line

        // you'll need to examine the InnerException property to get the stack trace
        // to the line that actually started the problem

        throw new InvalidOperationException("Watch your format string indexes.", ex);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Something else horrible happened. The exception: " + ex.Message);

        // do not do this, because the stack trace will be changed to point to
        // this location instead of the location where the exception
        // was originally thrown:
        throw ex; 
    }
}

static void Main()
{
    try
    {
        AskTheUltimateQuestion();
    }
    catch
    {
        // choose this kind of catch if you don't need any information about 
        // the exception that was caught

        // this block "eats" all exceptions instead of rethrowing them
    }
}

Вы можете фильтровать по типу исключений и даже по свойствам исключений (новый в C # 6.0, более длинный доступный в VB.NET (ссылка)):

Документация / C # / новые функции

Исключительные фильтры

Поскольку исключения C # 6.0 могут быть отфильтрованы с использованием оператора when .

Это похоже на использование простого if но не разматывает стек, если условие внутри when не выполняется.

пример

try
{ 
  // ...
}
catch (Exception e) when (e.InnerException != null) // Any condition can go in here.
{
  // ...
}

Такую информацию можно найти в функциях C # 6.0 здесь: Исключительные фильтры

Повторное исключение в блоке catch

В блоке catch ключевое слово throw может использоваться самостоятельно, без указания значения исключения, для восстановления только что пойманного исключения. Повторное исключение позволяет исходному исключению продолжать цепочку обработки исключений, сохраняя стек вызовов или связанные данные:

try {...}
catch (Exception ex) {
  // Note: the ex variable is *not* used
  throw;
}

Общим анти-шаблоном является вместо этого throw ex , что приводит к ограничению зрения следующего обработчика исключения для трассировки стека:

try {...}
catch (Exception ex) {
  // Note: the ex variable is thrown
  //  future stack traces of the exception will not see prior calls
  throw ex;  
}

В общем случае использование throw ex нежелательно, так как будущие обработчики исключений, которые проверяют трассировку стека, смогут видеть вызовы еще до throw ex . Опуская переменную ex и используя ключевое слово throw исходное исключение будет «пузыряться» .

Выбрасывание исключения из другого метода при сохранении его информации

Иногда вы хотите поймать исключение и выбросить его из другого потока или метода, сохраняя исходный стек исключений. Это можно сделать с помощью ExceptionDispatchInfo :

using System.Runtime.ExceptionServices;

void Main()
{
    ExceptionDispatchInfo capturedException = null;
    try
    {
        throw new Exception();
    }
    catch (Exception ex)
    {
        capturedException = ExceptionDispatchInfo.Capture(ex);
    }
    
    Foo(capturedException);
}

void Foo(ExceptionDispatchInfo exceptionDispatchInfo)
{
    // Do stuff

    if (capturedException != null)
    {
        // Exception stack trace will show it was thrown from Main() and not from Foo()
        exceptionDispatchInfo.Throw();
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow