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