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

StackOverflow https://stackoverflow.com/questions/117173

  •  02-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

Другие советы

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

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

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

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

Вы ясно указали мне на две вещи:

  1. Вы знаете, что архитектура сломана.
  2. Там тонны этого дерьма.

Я говорю:

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

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

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

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

Быстро провалиться

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

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

Итак, если бы это был 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() в код вручную). .Однако убедиться, что он изменил только те строки, которые должны были быть, может быть сложно (приходится пропускать объявления переменных, конструкции циклов и т. д., чтобы не нарушить сборку).

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

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

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

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

Как кто-то упомянул, 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();
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Забавный вопрос;очень ужасно.

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

Возясь с этим, я пытался пометить каждую строку и вернуться к одному улову, но без особого успеха.Однако, Кристофер нашел правильный способ сделать это.Есть некоторые интересное дополнительное обсуждение этого на Dot Net Thoughts и в Блог Майка Столла по .NET.

РЕДАКТИРОВАТЬ:Конечно.А try-catch / switch-goto Перечисленное решение фактически не скомпилируется, поскольку try метки выходят за рамки catch.Кто-нибудь знает, чего не хватает для компиляции чего-то подобного?

Вы можете автоматизировать это с помощью этапа предварительной обработки компилятора или, возможно, взломать Инструмент встроенного IL Майка Столла чтобы внести некоторую ошибку-невежество.

(Ответ Ориона Адриана об изучении Исключения и попытка установить следующую инструкцию тоже интересна.)

В общем, занятие интересное и поучительное.Конечно, вам придется решить, в какой момент усилия по моделированию ON ERROR RESUME NEXT перевешивают усилия по исправлению кода.:-)

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

К сожалению, вам, вероятно, не повезло.Возобновить при ошибке «Далее» — это устаревший вариант, который, как правило, категорически не рекомендуется и не имеет эквивалента моим знаниям в C#.

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

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

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

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

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

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

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

Хилите каждую строку по одной, «Окружите» try/catch.Это позволяет избежать упомянутого вами копирования и вставки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top