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

Я нашел несколько сбоев приложений c# в ответ на условия ошибки, такие как obj = null или obj.member = null. Много времени, obj из интерфейса 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. etc.

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

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!

Надежда эта помощь, С уважением, Том.


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

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

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

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 вместо string ресурса. Это вызвало ArgumentNullException на String.Format звонок. Это привело к тому, что исключение было поймано кодом, который просто продолжался.

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

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


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

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

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

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

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

...?


вы, конечно, не должны добавлять try catch everywhere

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

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

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

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

но это не останавливает его crshing, он просто позволяет захватить сбой


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

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

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


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

ли это хорошая идея, чтобы сделать это до вас, однако!


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

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

затем вы можете показать messagebox или другое уведомление, loog exeception и т. д. и продолжить работу без сбоев приложения.