Try-catch каждая строка кода без отдельных блоков try-catch - PullRequest
12 голосов
/ 22 сентября 2008

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

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

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

Умножается на сто. Некоторые из них могут работать, другие могут пойти не так, как надо. То, что вам нужно, это эквивалент C # «при возобновлении ошибки далее», в противном случае вы в конечном итоге будете копировать и вставлять пробные уловки вокруг множества строк кода.

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

Ответы [ 19 ]

45 голосов
/ 23 сентября 2008
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 );
22 голосов
/ 23 сентября 2008

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

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

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

19 голосов
/ 23 сентября 2008

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

Да, все верно, НИЧЕГО не делай.

Вы четко определили мне две вещи:

  1. Вы знаете, что архитектура разрушена.
  2. Существует тонна этой хрени.

Я говорю:

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

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

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

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

12 голосов
/ 23 сентября 2008

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

9 голосов
/ 23 сентября 2008

Fail Fast

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

7 голосов
/ 23 сентября 2008

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

Итак, если бы это был C ++, вы могли бы сделать что-то вроде этого:

#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 / C ++.

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

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

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

7 голосов
/ 23 сентября 2008

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

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

4 голосов
/ 23 сентября 2008

Как уже упоминалось, VB позволяет это. Как насчет того же в C #? Введите верный отражатель:

Это:

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();
    }
}
3 голосов
/ 23 сентября 2008

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

2 голосов
/ 23 сентября 2008

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

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

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

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

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

...