Попробуйте каждую строку кода без отдельных блоков try-catch

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

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

WidgetMaker.SetAlignment(57);
contactForm["Title"] = txtTitle.Text;
Casserole.Season(true, false);
((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;

Умножается на сто. Некоторые из них могут работать, другие могут ошибиться. Что вам нужно, это эквивалент С# "on error resume next", иначе вы собираетесь копировать и вставлять пробные уловы вокруг многих строк кода.

Как вы попытаетесь решить эту проблему?

Ответ 1

Совершенно очевидно, что вы напишете код в VB.NET, который на самом деле имеет On Error Resume Next и экспортирует его в от DLL до С#. Все остальное просто обжора  за наказание.

Ответ 2

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 );

Ответ 3

Рефакторинг в индивидуальные, хорошо известные методы:

AdjustFormWidgets();
SetContactTitle(txtTitle.Text);
SeasonCasserole();

Каждый из них защищен соответствующим образом.

Ответ 4

Я бы сказал, ничего не делать.

Да, верно, НИЧЕГО.

Вы ясно определили мне две вещи:

  • Вы знаете, что архитектура увязана.
  • Есть тонна этого дерьма.

Я говорю:

  • Ничего не делать.
  • Добавить глобальный обработчик ошибок, чтобы отправлять вам электронное письмо каждый раз, когда он идет стрелой.
  • Подождите, пока что-то не упадет (или не пройдет тест)
  • Исправьте (Refactoring при необходимости в пределах области страницы).
  • Повторяйте каждый раз, когда возникает проблема.

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

Как только вы начнете выигрывать войну, у вас будет лучшая ручка кода (из-за всего вашего рефакторинга) у вас будет лучшая идея для выигрышного дизайна для него.

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

Ответ 5

Fail Fast

Чтобы разработать, я думаю, я задаю вопрос. Если вы выбрали исключение, почему вы хотите, чтобы ваш код просто продолжался, как будто ничего не произошло? Либо вы ожидаете исключений в определенных ситуациях, и в этом случае вы пишете блок try-catch вокруг этого кода и обрабатываете их, либо возникает непредвиденная ошибка, и в этом случае вы должны предпочесть прекратить или повторить попытку приложения или выполнить сбой. Не продолжайте, как раненный зомби, стонущий "мозги".

Ответ 6

On Error Resume Next - действительно плохая идея в мире С#. Не добавив эквивалент On Error Resume Next, вам действительно поможет. Все, что вам нужно, это оставить вас в плохом состоянии, что может привести к более тонким ошибкам, потере данных и, возможно, повреждению данных.

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

Ответ 7

Это одна из вещей, для которой полезно использовать препроцессор. Вы можете определить макрос, который проглатывает исключения, а затем с быстрым 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() в код вручную), Удостоверившись, что он только изменил строки, которые он, как предполагается, мог быть затруднен (нужно пропустить объявления переменных, конструкции цикла и т.д., Чтобы вы не нарушили сборку).

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

Действительно, вы никогда не должны этого делать. Вам нужно найти причину ошибки и исправить ее. Проглатывание/игнорирование ошибок - это плохо, поэтому я думаю, что правильный ответ здесь: "Исправить ошибку, не игнорируйте ее!".:)

Ответ 8

Как уже упоминалось, 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();
    }
}

Ответ 9

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

Ответ 10

Если вы можете заставить компилятор предоставить вам дерево выражений для этого кода, вы можете изменить это дерево выражений, заменив каждый оператор новым блоком try-catch, который обертывает исходный оператор. Это не так надуманно, как кажется; для LINQ, С# получила возможность записывать лямбда-выражения в виде деревьев выражений, которые можно манипулировать в пользовательском коде во время выполнения.

Этот подход сегодня невозможен с .NET 3.5 - если не по какой-либо другой причине, кроме отсутствия "попытки" в System.Linq.Expressions. Однако это вполне может быть жизнеспособным в будущей версии С# после завершения объединения деревьев выражений DLR и LINQ.

Ответ 11

Вы можете использовать goto, но он все еще запутан.

Я на самом деле хотел какое-то однопользовательское приложение try-catch. Было бы полезно в некоторых случаях, например, добавить код регистрации или что-то, что вы не хотите прервать основной поток программы, если он терпит неудачу.

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

Ответ 12

Это может помочь вам определить части, которые имеют большинство проблем.

@JB King Спасибо за напоминание. В блоке приложения Logging есть событие Instrumentation, которое можно использовать для отслеживания событий, вы можете найти дополнительную информацию о документах библиотеки MS Enterprise.

Using (New InstEvent)
<series of statements> 
End Using

Все этапы этого использования будут прослеживаться в файле журнала, и вы можете проанализировать это, чтобы увидеть, где лог ломается (из-за того, что он был выброшен) и идентификация высоких нарушителей.

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

Ответ 13

Почему бы не использовать отражение в С#? Вы можете создать класс, который отражает код, и использовать строку #s в качестве подсказки для того, что добавить в каждый отдельный блок try/catch. Это имеет несколько преимуществ:

  • Это немного менее уродливое, так как на самом деле вам не нужно калечить исходный код, и вы можете использовать его только во время режимов отладки.
  • Вы узнаете что-то интересное о С# при его реализации.

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

Ответ 14

Веселый вопрос; очень страшно.

Было бы неплохо, если бы вы могли использовать макрос. Но это взорвано С#, поэтому вы можете решить его с помощью некоторой работы препроцессора или какого-либо внешнего инструмента, чтобы обернуть ваши линии в отдельные блоки 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 перевешивает усилия по исправлению кода.: -)

Ответ 15

Поймите ошибки в UnhandledException Event приложения. Таким образом, необработанные исключения могут даже регистрироваться в отношении отправителя и любой другой информации, которую разработчик будет разумным.

Ответ 16

К сожалению, вам, вероятно, не повезло. On Error Resume Next - это устаревший вариант, который обычно сильно обескуражен и не имеет эквивалента моим знаниям на С#.

Я бы порекомендовал оставить код в VB (похоже, что это был источник, учитывая ваш конкретный запрос для OnError ResumeNext) и взаимодействие с или с dll или exe С#, которое реализует любой новый код, который вам нужен. Затем выполните рефакторинг преформы, чтобы код был безопасным, и преобразуйте этот безопасный код в С#, как вы это делаете.

Ответ 17

Игнорирование всех причин, по которым вы хотели бы избежать этого.......

Если это просто необходимость держать # строк вниз, вы можете попробовать что-то вроде:

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
    }
}

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

Ответ 18

Вы можете посмотреть на интеграцию компонента обработки исключений Enterprise Library для одной идеи о том, как обрабатывать необработанные исключения.

Если это относится к приложениям ASP.Net, в вызове Global.asax есть функция "Application_Error", которая в большинстве случаев вызывает вызов с катастрофическим сбоем, как обычно.

Ответ 19

Погиб каждой линии, по одному, "Surround with" try/catch. Это позволяет избежать копирования, которое вы упомянули