Как я могу глотать все исключения и защитить мое приложение от катастрофического отказа?

Я нашел несколько сбоев приложения C# в ответ на состояния ошибки таким как obj = null или obj.member = null. Много времени, obj от интерфейса 3rdPartyApp. И вызванный и 3rdPartyApp и MyCsApp, разрушенный вместе.

Как я мог добавить обработку исключений во всех возможных областях так, чтобы мое приложение могло выжить в этих катастрофических ситуациях? Это - проблема добавить выгоду попытки ко ВСЕМ местам и восстановиться с ситуации.

Как я мог выполнить это способом, которое является реалистичным, надежным и пуленепробиваемым?

[Обновление: промышленное управление автоматизацией]

Структура:

GUI (asp.net, C++) - RuntimeApp (C++) - MyCsApp (cs) - 3rdPartyApp (сс)

Нормальная процедура:

  1. HostApp - (Подключение через Ethernet Cabele) - MyCsApp
  2. Оператор - GUI - RuntimeApp - MyCsApp

Ненормальные условия:

  1. Некоторый нестандартный порядок работы;
  2. некоторая аппаратная проблема произошла;
  3. и т.д.

Я должен обработать все аварийные условия. И самое главное, я должен думать, как восстановиться с ситуаций.

10
задан Nano HE 12 February 2010 в 05:13
поделиться

7 ответов

Было бы разумно сначала вылечить болезнь, выяснить, почему она вызывает сбой, и убедитесь, что код дает сбой из-за obj = null или аналогичный - использование обработки исключений и проглатывание всех исключений просто маскирует проблему ... Вот для чего он не используется! Похоже, что есть много запахов кода, которые вызывают сбои - Защита вашего приложения от сбоев - неправильный способ справиться с этим и только усугубляет ситуацию ...

Хорошо, вы можете следить за Джоном Сондерсом и pm100 предложение сделать это ... но обработайте это так, чтобы увидеть, в чем основная причина, не относитесь к нему как к «волшебной серебряной пуле», в конце концов, код, который взаимодействует со сторонним приложением, для тщательной отладки ...

например

object foo = null;
bar baz;

// ....
// foo is now set by thirdparty app

if (foo != null && foo is bar)  baz = (bar)foo as bar;

if (baz != null){

  // Continue on, baz is a legitimate instance of type 'bar'

}else{

  // Handle it gracefully or throw a *user defined exception*

}

Обратите внимание, как используется 'as' для проверки того, имеет ли 'foo' правильный тип для экземпляра 'bar' - теперь сравните с этим, это типичный код запах ...

object foo = null;
bar baz;

// foo is now set by thirdparty app - ARE YOU REALLY SURE ITS NON-NULL?
// IS IT REALLY OF TYPE 'BAR'?

baz = foo; // CRASH! BANG! WALLOP! KERRUNCH!
3
ответ дан 3 December 2019 в 14:34
поделиться

Вы не хотите перехватывать каждое исключение везде.

Вы хотите предотвратить «утечку» исключений из нижних уровней вашего приложения, где они могут убить приложение или повредить его.

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

ComplexBuilder cb = new ComplexBuilder();
try
{
    cb.AddOperation(...);  // Once building starts,
    cb.AddOperation(...);  // it's not safe to use cb
    cb.AddOperation(...);
}
catch (SpecificException ex)
{
    cb.Cleanup();          // until it's cleaned up
}

// Now safe to access cb, whether or not an exception was thrown

Я недавно столкнулся с приложением с похожим отношением. В этом заявлении был фрагмент, который считался «важным». Когда произошло это «важное» событие, должны были произойти и другие вещи, которые считались «не важными». Идея заключалась в том, что если было исключение в «неважной» части, то было необходимо, чтобы «важная» часть продолжалась.

Произошло то, что попытка чтения ресурса по какой-то причине не удалась. Это вернуло значение null вместо строкового ресурса.Это вызвало исключение ArgumentNullException в вызове String.Format . Это привело к тому, что исключение было перехвачено кодом, который только что продолжился.

Но между первым и последним исключением должен был быть выделен объект и должна была быть установлена ​​ссылка на объект. Но из-за исключения установка ссылки так и не произошла. В результате я увидел NullReferenceException , четыре уровня стека вверх и два файла .csproj от того места, где возникла реальная проблема.

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

19
ответ дан 3 December 2019 в 14:34
поделиться

AppDomain.UnHandledException и / или AppDomain.ThreadException - это события, на которые вы можете подписаться, чтобы перехватить необработанные исключения. Я не думаю, что вы можете использовать это, чтобы продолжить выполнение с того места, где оно было остановлено (и это, вероятно, в любом случае не будет хорошей идеей). Их можно использовать для проглатывания сообщения об ошибке, его регистрации и т. Д.

Однако решать, стоит ли это делать, решать вам!

0
ответ дан 3 December 2019 в 14:34
поделиться

Одним из способов избежать таких исключений является использование шаблона нулевого объекта .

Таким образом, вместо Account account = null; вы должны сделать Account account = Account.SpecialNullAccount; и в своем классе Account вы должны определить SpecialNullAccount как статический объект Account . Теперь, если вы попытаетесь использовать account.Name в каком-то несущественном коде (например, в коде регистрации), вы не получите Exception, вместо этого вы получите значение, например, «NO NAME», определенное в статическом экземпляр нулевого объекта.

Конечно, важно, чтобы такой объект ДЕЙСТВИТЕЛЬНО генерировал исключения в любом важном случае, например.PayInvoice () или objectContext.SaveChanges (), поэтому примите меры, чтобы это произошло.

0
ответ дан 3 December 2019 в 14:34
поделиться

вам, конечно же, не следует добавлять try catch везде

вам просто нужен перехват всех исключений верхнего уровня. Если это приложение с графическим интерфейсом, просто отобразите красивый диалог с кнопкой, говорящей «пожалуйста, сообщите в службу поддержки» (он может записать снимок трассировки стека на экран или в файл)

, если вам повезет, приложение может продолжить (повезло, поскольку у вас нет возможности узнать, действительно ли вы застряли в затруднительном положении)

обратите внимание, что вы также можете сделать это

        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        Forms.Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);

, но это не останавливает сбой, а просто позволяет зафиксировать сбой

{{1} }
4
ответ дан 3 December 2019 в 14:34
поделиться

Если это приложение Winforms, добавьте обработчики следующих событий в метод Main следующим образом

Application.ThreadException += Application_ThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

Затем вы можете показать окно сообщения или другое уведомление, просмотреть исключение и т.д. и продолжить работу без сбоя приложения.

0
ответ дан 3 December 2019 в 14:34
поделиться

Это то, чего не понимают многие разработчики. К тому моменту, когда ваш catch-all для исключений достигнет цели, ваше приложение уже рухнет. Произошло что-то неожиданное, что означает, что ваш код не предвидел этого, и, скорее всего, ситуация находится в неопределенном состоянии (т.е. вы не можете точно сказать, какая часть нарушающей функции завершилась в момент генерации исключения, вы не знаете, сколько данных было записано, какие биты были установлены в аппаратном обеспечении и т.д.). Безопасно ли продолжать работу? Стоит ли пытаться спасти данные пользователя? Кто знает!

Когда вы достигнете этого высокого уровня, который вы собираетесь обеспечить, вы не предотвратили крах вашего приложения. Вы просто решаете, что делать с крахом в этот момент. Вы можете вывести сообщение, отличное от стандартного:

Это приложение выполнило незаконную операцию

... но чем ваше пользовательское сообщение будет лучше?

Мы завершаем работу без предупреждения для внепланового обслуживания, но будьте будьте уверены, что это не имеет никакого отношения к дефектом в этом превосходном программном обеспечении

...?

7
ответ дан 3 December 2019 в 14:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: