Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharp_Prog_Guide.doc
Скачиваний:
16
Добавлен:
16.11.2019
Размер:
6.22 Mб
Скачать

Использование исключений

В языке C# ошибки в программе во время выполнения передаются через программу посредством механизма, называемого исключениями. Исключения создаются кодом, который встречает ошибку, и перехватываются кодом, который может исправить ее. Исключения могут создаваться средой CLR платформы .NET Framework или кодом в программе. В случае исключения, оно передается по стеку вызовов, пока не будет найден оператор catch для исключения. Не перехваченные исключения обрабатываются универсальным обработчиком исключений, предоставляемым системой, который открывает диалоговое окно.

Исключения представляются посредством классов, производных от Exception. Такой класс устанавливает тип исключения и содержит свойства с подробными сведениями об исключении. При генерации исключения создается экземпляр класса, производного от исключения, настраиваются свойства исключения (необязательно), а затем при помощи ключевого слова throw создается объект. Пример.

------

После генерации исключения среда выполнения проверяет текущий оператор и устанавливает, находится ли он в блоке try. Если это так, то проверяются любые блоки catch, связанные с блоком try, и устанавливается возможность перехвата ими исключения. Как правило, блоки Catch задают тип исключений; если тип блока catch соответствует типу исключения или базовому классу исключения, блок catch сможет обработать метод. Пример.

----

If the statement that throws an exception is not within a try block or if the try block that encloses it has no matching catch block, the runtime checks the calling method for a try statement and catch blocks. The runtime continues up the calling stack, searching for a compatible catch block. After the catch block is found and executed, control is passed to the first statement after the catch block.

A try statement can contain more than one catch block. The first catch statement that can handle the exception is executed; any following catch statements, even if they are compatible, are ignored. For example:

static void TestCatch2()

{

try

{

TestThrow();

}

catch (System.Exception ex)

{

System.Console.WriteLine(ex.ToString()); // this block will be executed

}

//catch (System.Exception ex)

//{

// System.Console.WriteLine(ex.ToString()); // this block will NOT be executed

//}

System.Console.WriteLine("Done"); // this statement is executed after the catch block

}

Before the catch block is executed, the try blocks that have been evaluated by the runtime and the try block that contains the compatible catch block, are checked for finally blocks. Finally blocks enable the programmer to clean up any ambiguous state that could be left over from an aborted try block, or to release any external resources (such as graphics handles, database connections or file streams) without waiting for the garbage collector in the runtime to finalize the objects. For example:

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

Оператор try может содержать несколько блоков catch. Выполняется первый оператор catch, который может обработать исключение; все последующие операторы catch, даже если они совместимы – пропускаются. Пример.

-----

Перед выполнением блока catch, блоки try, вычисленные средой выполнения, и блок try, содержащий совместимый блок catch, проверяются на наличие блоков finally. Блоки finally позволяют программисту очищать любое неоднозначное состояние, которое могло быть оставлено отмененным блоком try, или освобождать любые внешние ресурсы (такие как обработчики графики, подключения к базам данным или потоки файлов) не дожидаясь сборщика мусора времени выполнения для завершения объектов. Пример.

static void TestFinally()

{

System.IO.FileStream file = null;

//Change the path to something that works on your machine

System.IO.FileInfo fileInfo = new System.IO.FileInfo(@"C:\file.txt");

try

{

file = fileInfo.OpenWrite();

file.WriteByte(0xF);

}

finally

{

// Closing the file allows you to reopen it immediately - otherwise IOException is thrown.

if (file != null)

{

file.Close();

}

}

try

{

file = fileInfo.OpenWrite();

System.Console.WriteLine("OpenWrite() succeeded");

}

catch (System.IO.IOException)

{

System.Console.WriteLine("OpenWrite() failed");

}

}

If WriteByte() threw an exception, the code in the second try block that tries to reopen the file would fail if file.Close() is not called, and the file would remain locked. Because finally blocks are executed even if an exception is thrown, the finally block in the previous example allows for the file to be closed correctly and helps avoid an error.

If no compatible catch block is found on the call stack after an exception is thrown, one of three things occurs:

  • If the exception is within a destructor, the destructor is aborted and the base destructor, if any, is called.

  • If the call stack contains a static constructor, or a static field initializer, a TypeInitializationException is thrown, with the original exception assigned to the InnerException property of the new exception.

  • If the start of the thread is reached, the thread is terminated.

----

Если WriteByte() сгенерировал исключение, код во втором блоке try, пытающийся повторно открыть файл, не будет выполнен, если file.Close() не вызван, и файл останется заблокированным. Так как блоки finally выполняются даже в случае генерации исключения, блок finally в предыдущем примере предусматривает правильное закрытие файла и помогает избежать ошибок.

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

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

  • Если в стеке вызовов содержится статический конструктор или статический инициализатор поля, генерируется TypeInitializationException и исходное исключение присваивается свойству InnerException нового исключения.

  • По достижении начала потока он прерывается.

Exception Handling

A try block is used by C# programmers to partition code that may be affected by an exception, and catch blocks are used to handle any resulting exceptions. A finally block can be used to execute code regardless of whether an exception is thrown. This situation is sometimes necessary because code that follows a try/catch construct will not be executed if an exception is thrown. A try block must be used with either a catch or a finally block, and can include multiple catch blocks. For example:

try

{

// Code to try here.

}

catch (SomeSpecificException ex)

{

// Code to handle exception here.

// Only catch exceptions you know how to handle.

// Never catch base class System.Exception.

}

try

{

// Code to try here.

}

finally

{

// Code to execute after try here.

}

try

{

// Code to try here.

}

catch (SomeSpecificException ex)

{

// Code to handle exception here.

}

finally

{

// Code to execute after try (and possibly catch) here.

}

A try statement without a catch or finally block will cause a compiler error.