Исключение исключений .NET неожиданно null
Ниже приведено объяснение того, что происходит
У меня действительно странная проблема, в которой исключение было пустым.
В коде используется MEF и сложно сообщить о ошибках композиции. С помощью отладчика я вижу, как генерируется исключение (InvalidOperationException
), но когда он пойман последним блоком catch в коде ниже переменной ex
, имеет значение null. Это верно как в отладчике, так и при нормальном выполнении кода.
static T ResolveWithErrorHandling<T>() where T : class
{
try
{
IocContainer.Compose(Settings.Default.IocConfiguration);
return IocContainer.Resolve<T>();
}
catch (ReflectionTypeLoadException ex)
{
// ... special error reporting for ReflectionTypeLoadException
}
catch (Exception ex)
{
// ex is null - that should not be possible!
// ... general error reporting for other exception types
}
return null;
}
Код, который я заменил комментариями, - это действительно простой код для форматирования сообщения об ошибке. Ничего странного там не происходит.
Я попытался изменить код, чтобы узнать, какой эффект может иметь:
- Если я удаляю первый блок catch (
ReflectionTypeLoadException
), исключение, пойманное в конечном блоке catch, больше не равно null.
- Если я поймаю другой тип исключения в первом блоке catch, исключение, пойманное в конечном блоке catch, больше не равно null.
- Если я добавлю блок catch для
InvalidOperationException
в качестве первого блока catch, исключение, пойманное в этом блоке, не является нулевым.
- Если я добавлю блок catch для
InvalidOperationException
между двумя блоками catch, исключение, пойманное в этом блоке, равно null.
В проекте используются Кодовые контракты, а код, сгенерированный компилятором, подвергается последующей обработке для проверки контрактов. К сожалению, я не нашел способ избавиться от этого для целей тестирования, не выполняя крупную операцию по проекту.
Мое текущее обходное решение состоит в том, чтобы не ловить ReflectionTypeLoadException
и вместо этого входить в тип ex
в общий обработчик исключений.
Что может быть объяснением этого "невозможного" поведения? Что происходит с блоком catch ReflectionTypeLoadException
?
Смутно исключение не является нулевым, и оно не может быть нулевым по стандарту С# 15.9.5.
Однако использование кодовых контрактов в проекте может испортить отображение локальных переменных в отладчике, потому что код IL, сгенерированный компилятором, может быть переписан кодовыми контрактами поэтому последний IL немного не синхронизирован с информацией об отладке. В моем случае переменная ex
отображается как null, даже если она отсутствует. Несчастный характер сообщения об ошибках, имевший место прямо перед завершением приложения, означал, что я полагал, что сообщение об ошибке не будет вызвано в результате того, что ex
имеет значение null и ex.Message
бросает NullReferenceException
внутри моего блока catch. Используя отладчик, я смог "проверить", что ex
имеет значение null, за исключением того, что он фактически не был нулевым.
Моя путаница усугублялась тем фактом, что блокировка catch для ReflectionTypeLoadException
, похоже, влияет на проблему с отображением отладки.
Спасибо всем, кто ответил.
Ответы
Ответ 1
Просто столкнулся с этой же проблемой. Наконец, я узнал, что я выбрал разные исключения с тем же именем, что и вы:
catch (ReflectionTypeLoadException ex)
{
// ...
}
catch (Exception ex)
{
// ex is not null!
// ...
}
Оба названы "ex". Изменение одного из обоих имен решило эту проблему для меня, например:
catch (ReflectionTypeLoadException reflectionEx)
{
// ...
}
catch (Exception ex)
{
// ex is null - that should not be possible!
// ...
}
Ответ 2
Я столкнулся с той же проблемой. В моем случае переименование переменной исключения (например, ex = > ex1) позволило мне поймать любое исключение...
Ответ 3
Вы должны проверить, что в какой-то момент IocContainer ловит Exception ex
throws ex.InnerException
, не проверяя, имеет ли он значение null.
С# счастливо принимает throw null
и заканчивается на catch (Exception)
.
Ответ 4
Я столкнулся с той же проблемой. Исключение было равным null при просмотре в отладчике, даже если был обнаружен правильный тип исключения - UpdateException. Я мог просмотреть исключение, открыв помощник исключения.
Как только я отключил "Выполнять проверку выполнения времени выполнения", были обнаружены исключения, которые больше не равны нулю. Я активно использовал кодовые контракты для перехода на год и не видел этой проблемы до того, как недавно начал работать с EF 4.1 в этом конкретном проекте, но я не знаю, была ли EF контрольной переменной в отношении исключенных исключений, которые были исключены.
Ответ 5
Исключение на самом деле не пустое, это проблема с отладчиком.
Кодовые контракты (ccrewrite) изменяют коды операций IL и что возмущает отладчик, потому что opcodes leave.s преобразуются в op opodes.
Оба кода операций имеют разные размеры, а адреса инструкций меняются, поэтому отладчик теряется, когда имена исключений одинаковы.
Вы можете использовать $exception в отладчике, чтобы обойти проблему.
Ответ 6
У меня тоже такая же ситуация. Это было ошибкой отладчика Eclipse. (Действительно, эта ситуация может быть только результатом некоторой ошибки отладчика.)
Перезапуск Eclipse был достаточным - исключение среды выполнения становится нормальным, а не нулевым. Другие отладчики могут быть не такими добрыми.