Как я могу проглотить все исключения и защитить мое приложение от сбоев? - PullRequest
10 голосов
/ 12 февраля 2010

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

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

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

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

Структура:

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

Обычная процедура:

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

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

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

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

Ответы [ 7 ]

19 голосов
/ 12 февраля 2010

Вы не хотите отловить все исключения везде.

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

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

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

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

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

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

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

7 голосов
/ 12 февраля 2010

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

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

Это приложение выполнило недопустимую операцию

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

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

...

4 голосов
/ 12 февраля 2010

Вы, конечно, не должны добавлять попробовать поймать везде

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

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

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

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

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

3 голосов
/ 12 февраля 2010

Было бы целесообразно сначала вылечить болезнь, выяснить, почему она вызывает сбой, убедиться, что код сбоя происходит из-за 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!
0 голосов
/ 12 февраля 2010

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

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

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

0 голосов
/ 12 февраля 2010

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

Является ли это хорошей идеей, решать только вам!

0 голосов
/ 12 февраля 2010

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

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

Конечно, важно, чтобы такой объект выкидывал исключения в любом важном случае, например .PayInvoice () или objectContext.SaveChanges (), поэтому примите меры, чтобы это произошло.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...