Ответ 1
Совершенно очевидно, что вы напишете код в VB.NET, который на самом деле имеет On Error Resume Next и экспортирует его в от DLL до С#. Все остальное просто обжора за наказание.
У меня в настоящее время нет этой проблемы, но вы никогда не знаете, и эксперименты с мышью всегда забавны.
Игнорируя очевидные проблемы, которые вам придется иметь с вашей архитектурой, даже пытаясь сделать это, предположим, что у вас был какой-то ужасно написанный код другого проекта, и вам нужно было сделать пучок широких и разнообразных операций в одном и том же кодовом блоке, например:
WidgetMaker.SetAlignment(57);
contactForm["Title"] = txtTitle.Text;
Casserole.Season(true, false);
((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;
Умножается на сто. Некоторые из них могут работать, другие могут ошибиться. Что вам нужно, это эквивалент С# "on error resume next", иначе вы собираетесь копировать и вставлять пробные уловы вокруг многих строк кода.
Как вы попытаетесь решить эту проблему?
Совершенно очевидно, что вы напишете код в VB.NET, который на самом деле имеет On Error Resume Next и экспортирует его в от DLL до С#. Все остальное просто обжора за наказание.
public delegate void VoidDelegate();
public static class Utils
{
public static void Try(VoidDelegate v) {
try {
v();
}
catch {}
}
}
Utils.Try( () => WidgetMaker.SetAlignment(57) );
Utils.Try( () => contactForm["Title"] = txtTitle.Text );
Utils.Try( () => Casserole.Season(true, false) );
Utils.Try( () => ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true );
Рефакторинг в индивидуальные, хорошо известные методы:
AdjustFormWidgets();
SetContactTitle(txtTitle.Text);
SeasonCasserole();
Каждый из них защищен соответствующим образом.
Я бы сказал, ничего не делать.
Да, верно, НИЧЕГО.
Вы ясно определили мне две вещи:
Я говорю:
У вас будет это прояснено в кратчайшие сроки, если это так плохо. Да, я знаю, что это звучит сосать, и вы можете сначала вытащить свои волосы с помощью исправлений, но это позволит вам исправить код нуждающегося/багги до (большого) количества кода который фактически может работать независимо от того, насколько он выглядит дерьмовым.
Как только вы начнете выигрывать войну, у вас будет лучшая ручка кода (из-за всего вашего рефакторинга) у вас будет лучшая идея для выигрышного дизайна для него.
Попытка обернуть все это в пузырчатую пленку, вероятно, займет много времени, и вы все равно не будете ближе к устранению проблем.
Чтобы разработать, я думаю, я задаю вопрос. Если вы выбрали исключение, почему вы хотите, чтобы ваш код просто продолжался, как будто ничего не произошло? Либо вы ожидаете исключений в определенных ситуациях, и в этом случае вы пишете блок try-catch вокруг этого кода и обрабатываете их, либо возникает непредвиденная ошибка, и в этом случае вы должны предпочесть прекратить или повторить попытку приложения или выполнить сбой. Не продолжайте, как раненный зомби, стонущий "мозги".
On Error Resume Next
- действительно плохая идея в мире С#. Не добавив эквивалент On Error Resume Next
, вам действительно поможет. Все, что вам нужно, это оставить вас в плохом состоянии, что может привести к более тонким ошибкам, потере данных и, возможно, повреждению данных.
Но чтобы дать вопросчику должное, вы могли бы добавить глобальный обработчик и проверить TargetSite, чтобы узнать, какой метод был обработан. Тогда вы могли бы, по крайней мере, знать, в какой строке он был связан. Следующая часть должна была попытаться выяснить, как установить "следующий оператор" так же, как это делает отладчик. Надеюсь, ваш стек не будет разворачиваться в этот момент, или вы можете его воссоздать, но это, безусловно, стоит того. Однако, учитывая этот подход, код должен запускаться в режиме отладки каждый раз, чтобы вы включали ваши символы отладки.
Это одна из вещей, для которой полезно использовать препроцессор. Вы можете определить макрос, который проглатывает исключения, а затем с быстрым script добавить этот макрос ко всем строкам.
Итак, если это С++, вы можете сделать что-то вроде этого:
#define ATTEMPT(x) try { x; } catch (...) { }
// ...
ATTEMPT(WidgetMaker.SetAlignment(57));
ATTEMPT(contactForm["Title"] = txtTitle.Text);
ATTEMPT(Casserole.Season(true, false));
ATTEMPT(((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true);
К сожалению, не многие языки, похоже, содержат препроцессор, такой как C/С++.
Вы можете создать свой собственный препроцессор и добавить его как шаг предварительной сборки. Если вам кажется, что вы полностью автоматизировали его, вы, вероятно, могли бы написать препроцессор, который бы взял фактический файл кода и сам добавить материал try/catch (так что вам не нужно добавлять эти блоки ATTEMPT() в код вручную), Удостоверившись, что он только изменил строки, которые он, как предполагается, мог быть затруднен (нужно пропустить объявления переменных, конструкции цикла и т.д., Чтобы вы не нарушили сборку).
Однако, я думаю, что это ужасные идеи, и их никогда не следует делать, но вопрос был задан.:)
Действительно, вы никогда не должны этого делать. Вам нужно найти причину ошибки и исправить ее. Проглатывание/игнорирование ошибок - это плохо, поэтому я думаю, что правильный ответ здесь: "Исправить ошибку, не игнорируйте ее!".:)
Как уже упоминалось, VB позволяет это. Как это сделать в С#? Введите надежный отражатель:
Это:
Sub Main()
On Error Resume Next
Dim i As Integer = 0
Dim y As Integer = CInt(5 / i)
End Sub
Переведено следующим образом:
public static void Main()
{
// This item is obfuscated and can not be translated.
int VB$ResumeTarget;
try
{
int VB$CurrentStatement;
Label_0001:
ProjectData.ClearProjectError();
int VB$ActiveHandler = -2;
Label_0009:
VB$CurrentStatement = 2;
int i = 0;
Label_000E:
VB$CurrentStatement = 3;
int y = (int) Math.Round((double) (5.0 / ((double) i)));
goto Label_008F;
Label_0029:
VB$ResumeTarget = 0;
switch ((VB$ResumeTarget + 1))
{
case 1:
goto Label_0001;
case 2:
goto Label_0009;
case 3:
goto Label_000E;
case 4:
goto Label_008F;
default:
goto Label_0084;
}
Label_0049:
VB$ResumeTarget = VB$CurrentStatement;
switch (((VB$ActiveHandler > -2) ? VB$ActiveHandler : 1))
{
case 0:
goto Label_0084;
case 1:
goto Label_0029;
}
}
catch (object obj1) when (?)
{
ProjectData.SetProjectError((Exception) obj1);
goto Label_0049;
}
Label_0084:
throw ProjectData.CreateProjectError(-2146828237);
Label_008F:
if (VB$ResumeTarget != 0)
{
ProjectData.ClearProjectError();
}
}
Перепишите код. Попытайтесь найти наборы утверждений, которые логически зависят друг от друга, так что, если кто-то терпит неудачу, то следующие не имеют смысла и убирают их в свои собственные функции и ставят вокруг них пробные уловы, если вы хотите проигнорировать результат и продолжайте.
Если вы можете заставить компилятор предоставить вам дерево выражений для этого кода, вы можете изменить это дерево выражений, заменив каждый оператор новым блоком try-catch, который обертывает исходный оператор. Это не так надуманно, как кажется; для LINQ, С# получила возможность записывать лямбда-выражения в виде деревьев выражений, которые можно манипулировать в пользовательском коде во время выполнения.
Этот подход сегодня невозможен с .NET 3.5 - если не по какой-либо другой причине, кроме отсутствия "попытки" в System.Linq.Expressions. Однако это вполне может быть жизнеспособным в будущей версии С# после завершения объединения деревьев выражений DLR и LINQ.
Вы можете использовать goto, но он все еще запутан.
Я на самом деле хотел какое-то однопользовательское приложение try-catch. Было бы полезно в некоторых случаях, например, добавить код регистрации или что-то, что вы не хотите прервать основной поток программы, если он терпит неудачу.
Я подозреваю, что что-то может быть сделано с некоторыми функциями, связанными с linq, но на самом деле у них нет времени для изучения. Если бы вы могли просто найти способ обернуть оператор как анонимную функцию, а затем использовать другой, чтобы вызвать это в блоке try-catch, это сработало бы... но не уверен, что это возможно только.
Это может помочь вам определить части, которые имеют большинство проблем.
@JB King Спасибо за напоминание. В блоке приложения Logging есть событие Instrumentation, которое можно использовать для отслеживания событий, вы можете найти дополнительную информацию о документах библиотеки MS Enterprise.
Using (New InstEvent)
<series of statements>
End Using
Все этапы этого использования будут прослеживаться в файле журнала, и вы можете проанализировать это, чтобы увидеть, где лог ломается (из-за того, что он был выброшен) и идентификация высоких нарушителей.
Рефакторинг - это действительно ваш лучший выбор, но если у вас есть много, это может помочь вам определить худших преступников.
Почему бы не использовать отражение в С#? Вы можете создать класс, который отражает код, и использовать строку #s в качестве подсказки для того, что добавить в каждый отдельный блок try/catch. Это имеет несколько преимуществ:
Я бы рекомендовал против любого из этого, если, конечно, вы не берете на себя обслуживание someelses, и вам нужно получить дескриптор исключений, чтобы вы могли их исправить. Возможно, будет интересно писать.
Веселый вопрос; очень страшно.
Было бы неплохо, если бы вы могли использовать макрос. Но это взорвано С#, поэтому вы можете решить его с помощью некоторой работы препроцессора или какого-либо внешнего инструмента, чтобы обернуть ваши линии в отдельные блоки try-catch. Не уверен, что вы имели в виду, что вы не хотели вручную обертывать их или что вы хотели полностью избежать try-catch.
Беседуя с этим, я пробовал маркировать каждую строку и прыгать назад из одного улова, без большой удачи. Однако Кристофер раскрыл правильный способ сделать это. Там интересное дополнительное обсуждение этого в Dot Net Thoughts и Майк Блог Stall.NET.
EDIT: Конечно. Вышеуказанное решение try-catch
/switch-goto
не будет компилироваться, так как метки try
недоступны в catch
. Кто-нибудь знает, чего не хватает, чтобы сделать что-то подобное этой компиляции?
Вы можете автоматизировать это с помощью этапа препроцессора компилятора или, возможно, взломать Mike Stall Inline IL tool, чтобы ввести некоторое игнорирование ошибок.
(Ответ Ориона Адриана об изучении Исключения и попытка установить следующую инструкцию тоже интересна.)
В целом, это похоже на интересное и поучительное упражнение. Конечно, вам нужно будет решить, в какой момент попытка имитировать ON ERROR RESUME NEXT перевешивает усилия по исправлению кода.: -)
Поймите ошибки в UnhandledException Event приложения. Таким образом, необработанные исключения могут даже регистрироваться в отношении отправителя и любой другой информации, которую разработчик будет разумным.
К сожалению, вам, вероятно, не повезло. On Error Resume Next - это устаревший вариант, который обычно сильно обескуражен и не имеет эквивалента моим знаниям на С#.
Я бы порекомендовал оставить код в VB (похоже, что это был источник, учитывая ваш конкретный запрос для OnError ResumeNext) и взаимодействие с или с dll или exe С#, которое реализует любой новый код, который вам нужен. Затем выполните рефакторинг преформы, чтобы код был безопасным, и преобразуйте этот безопасный код в С#, как вы это делаете.
Игнорирование всех причин, по которым вы хотели бы избежать этого.......
Если это просто необходимость держать # строк вниз, вы можете попробовать что-то вроде:
int totalMethodCount = xxx; for(int counter = 0; counter < totalMethodCount; counter++) { try { if (counter == 0) WidgetMaker.SetAlignment(57); if (counter == 1) contactForm["Title"] = txtTitle.Text; if (counter == 2) Casserole.Season(true, false); if (counter == 3) ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true; } catch (Exception ex) { // log here } }
Однако, если вы попытаетесь повторно использовать любой из результатов вызовов, вам придется следить за областью переменных.
Вы можете посмотреть на интеграцию компонента обработки исключений Enterprise Library для одной идеи о том, как обрабатывать необработанные исключения.
Если это относится к приложениям ASP.Net, в вызове Global.asax есть функция "Application_Error", которая в большинстве случаев вызывает вызов с катастрофическим сбоем, как обычно.
Погиб каждой линии, по одному, "Surround with" try/catch. Это позволяет избежать копирования, которое вы упомянули