Подтвердить что ты не робот

Исключение исключений .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, похоже, влияет на проблему с отображением отладки.

Спасибо всем, кто ответил.

4b9b3361

Ответ 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 был достаточным - исключение среды выполнения становится нормальным, а не нулевым. Другие отладчики могут быть не такими добрыми.