Исключения, сгенерированные в блоке finally, финализаторах

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using System;
using System.Collections;
public class Entrypoint
{
static void Main()  {
try {
try {
ArrayList list = new ArrayList ();
list.Add( 1 ) ;
Console.WriteLine ( "Элемент 10 = {0}", list[10]  );
}
finally {
Console.WriteLine ( "Очистка..." );
throw new Exception ( "Лучше сгенерировать исключение" );
}
catch( ArgumentOutOfRangeException )  {
Console.WriteLine( "Аргумент вышел за допустимые пределы!" );
}
catch {
Console.WriteLine( "Готово" );
}

Первое исключение, ArgumentOutOfRangeException, просто теряется, а новое исключение распространяется по стеку. Ясно, что это нежелательно. Никогда не теряйте след исключений, поскольку тогда практически невозможно определить, что именно вызвало исключение в самом начале.

Исключения, сгенерированные в финализаторах

В действительности деструкторы С# являются не детерминированными деструкторами, а финализаторами CLR. Финализаторы исполняются в контексте потока финализатора, который на самом деле является контекстом произвольного потока. Если финализатор должен генерировать исключение, то CLR может не знать, как обработать эту ситуацию, и просто прервет поток (и процесс).

Рассмотрим следующий код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
public class Person {
-Person ()  {
Console.WriteLine ( "Очистка Person..." );
Console.WriteLine ( "Очистка Person завершена..." );
}
public class Employee : Person {
-Employee ()  {
Console.WriteLine ( "Очистка Employee ..." );
object obj = null;
// Следующий код сгенерирует исключение.
Console.WriteLine( obj.ToString()  );
Console.WriteLine ( "Очистка Employee завершена..." );
}
public class Entrypoint
{
static void Main()  {
Employee emp = new Employee();
emp = null;
}

Ниже показан вывод, полученный в результате выполнения этого кода:

Очистка Employee…
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object, at Employee.Finalize()

Необработанное исключение: System.NullReferenceException: Объектная ссылка не установлена в экземпляр объекта.
at Employee.Finalize()

Очистка Person…
Очистка Person завершена…

При запуске этого примера в средах .NET 1.1, .NET 2.0 и последующих версий обнаружится небольшие отличия в поведении. В .NET 1.1 исключение “проглатывается” вместе с выводом на консоль, и выполнение продолжается дальше. Начиная с версии .NET 2.0, исполняющая среда отобразит знакомое диалоговое окно отладки JIT с запросом о необходимости проведения отладки приложения. Проблема в том, что на ответ выделяется мало времени, и работа приложения прекращается.

Нужно любой ценой избегать намеренной генерации исключений в финализаторах, поскольку тем самым можно прервать процесс.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100