Какова лучшая альтернатива «При ошибке возобновить дальше» для C #? - PullRequest
13 голосов
/ 28 января 2011

Если я добавлю пустые блоки catch для своего кода C #, это будет эквивалентно выражению VB.NET «On Error Resume Next».

try
{
    C# code;
}

catch(exception)
{
}

Я спрашиваю об этом потомуЯ должен преобразовать код VB.NET в C #, и старый код содержит ~ 200 операторов «On Error Resume Next», хотя я использую правильный try {} catch {} в своем новом коде, но есть ли лучшая альтернатива?

Ответы [ 11 ]

19 голосов
/ 28 января 2011

Я обнаружил, что программисты на VB часто засоряли код множеством On Error Resume Next утверждений из-за (плохой) привычки.Я бы предложил начать с no исключенных исключений и посмотреть, что на самом деле ломается.Там может быть не так много вопросов, как вы думаете.И наоборот, чем больше регрессионного тестирования вы можете сделать, тем лучше;могут быть некоторые крайние случаи, которые работают только тогда, когда ошибки игнорируются.

В конечном счете, вам необходимо определиться со стратегией обработки ошибок, будь то постепенное развертывание во многих блоках try / catch или позволить ошибкам просачиваться кобработчик верхнего уровня (обе стратегии имеют свое применение).

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

6 голосов
/ 28 января 2011

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

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

5 голосов
/ 28 января 2011

Нет, это не то же самое.

При использовании On Error Resume Next, VB будет переходить к следующей строке, если произойдет ошибка.При использовании try / catch выполнение переходит к блоку catch, если возникает ошибка (исключение).

5 голосов
/ 28 января 2011

Вам нужно проанализировать On Error Resume Next утверждения один за другим и посмотреть, какова их цель. Некоторые могут быть просто неаккуратным кодом, но есть веские причины для On Error Resume Next в коде Visual Basic 6.0.

Некоторые примеры использования On Error Resume Next в коде Visual Basic 6.0:

  • Чтобы проверить, существует ли данный ключ в коллекции Visual Basic 6.0. Единственный способ сделать это - получить доступ к элементу по ключу и обработать ошибку, которая возникает, если ключ не существует. При конвертации в .NET вы можете заменить это проверкой на наличие ключа.

  • Разбор строки в целое число. В .NET вы можете использовать TryParse .

4 голосов
/ 21 июня 2012

Хотя On Error Resume Next определенно злоупотребляют больше, чем законно, есть места, где это было бы полезно даже в VB.NET.

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

«Правильный» способ сделать это с VB.NET - определить, какие свойства принтера поддерживаются каждой версией Excel, прочитать используемую версию и назначить только свойства, реализованные в этой версии. Это потребует много исследований и некоторого кода, но все это принесет мало пользы. On Error Resume Next было бы более практичным решением.

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

3 голосов
/ 11 декабря 2015

«On Error Resume Next» разрешает «Встроенную обработку ошибок», которая является обработкой ошибок экспертного уровня в VB.Концепция состоит в том, чтобы обрабатывать ошибки построчно, либо выполняя действие, основанное на ошибке, либо игнорируя ошибку, когда это выгодно, - но запуская код в той последовательности, в которой он написан, и не используя переходы кода.

К сожалению, многие новички использовали «On Error Resume Next», чтобы скрыть свою неспособность или лень от тех, кто использует свои приложения, игнорируя все ошибки.Try/catch - обработка ошибок на уровне блоков, которая в мире до .NET была промежуточной по дизайну и реализации.

Проблема с «On Error Resume Next» в VB.NET заключается в том, что он загружает объект err в каждую строку исполняемого кода и, следовательно, медленнее, чем try/catch.Я несколько встревожен, что этот форум проверил и продвинул бессмысленный ответ, который утверждал, что использование On Error Resume Next - плохая привычка и мусор кода.Это форум C #;действительно ли это нужно для программистов C # делать снимки на другом языке, в котором они плохо разбираются?

https://msdn.microsoft.com/en-us/library/aa242093(v=vs.60).aspx

Говорят, что программисты среднего уровня C #, не имеющие реального опыта работы с VB, не должны пытаться держать C # в подавленном состоянии и ограничивать функциональность из-за своего странного презрения к другой «Microsoft Net»язык, рассмотрим следующий код:

//-Pull xml from file and dynamically create a dataset.
 string strXML = File.ReadAllText(@"SomeFilePath.xml");
 StringReader sr = new StringReader(strXML);
 DataSet dsXML = new DataSet();
 dsXML.ReadXml(sr);

string str1 = dsXML.Tables["Table1"].Rows[0]["Field1"].ToString();
string str2 = dsXML.Tables["Table2"].Rows[0]["Field2"].ToStrin();
string str3 = dsXML.Tables["Table3"].Rows[0]["Field3"].ToStrin();
string str4 = dsXML.Tables["Table4"].Rows[0]["Field4"].ToString();
string str5 = dsXML.Tables["Table5"].Rows[0]["Field5"].ToString();

Если XML обычно имеет значение для Field3, но иногда нет;Я собираюсь получить досадную ошибку, что таблица не содержит поля.Мне было бы наплевать, если это не так, потому что это не обязательные данные.В этом случае ON Error Resume Next позволит мне просто игнорировать ошибку, и мне не придется кодировать каждую строку кода, устанавливая переменные, проверяющие наличие таблицы, строки и столбца с помощью методов Contains.Это маленький пример;Я мог бы получить тысячи таблиц, столбцов, строк строк из больших файлов.Также предположим, что строковые переменные должны быть заполнены таким образом.Это необработанный код, и возникнут проблемы.

Рассмотрим ошибку VB.NET и ON. Возобновите следующую реализацию:

On Error Resume Next

        'Pull Xml from file And dynamically create a dataset.
        Dim strXML As String = File.ReadAllText("SomeFilePath.xml")
        Dim srXmL As StringReader = New StringReader(strXML)
        Dim dsXML As DataSet = New DataSet()
        dsXML.ReadXml(srXmL)

        'Any error above will kill processing. I can ignore the first two errors and only need to worry about dataset loading the XML.
        If Err.Number <> 0 Then
            MsgBox(Err.Number & Space(1) & Err.Description)
            Exit Sub 'Or Function
        End If

        Dim str1 As String = dsXML.Tables("Table1").Rows(1)("Field1").ToString()
        Dim str2 As String = dsXML.Tables("Table2").Rows(2)("Field2").ToString()
        Dim str3 As String = dsXML.Tables("Table3").Rows(3)("Field3").ToString()
        Dim str4 As String = dsXML.Tables("Table4").Rows(4)("Field4").ToString()

В приведенном выше коде необходимо было обработать только одну возможнуюсостояние ошибки;хотя до обработки третьей ошибки было две ошибки.Требуется разработка RAD On Error Resume Next.C # - мой выбор языков, но по многим причинам он не такой RAD, как VB.Я надеюсь, что все программисты понимают, что несколько основных языков (например, C) просто работают и не останавливают выполнение из-за необработанных ошибок;работа разработчиков - проверять их там, где они считают это необходимым.On Error Resume Next - это самая близкая вещь к этой парадигме в мире Microsoft.

К счастью, .NET действительно предлагает много продвинутых вариантов для решения этих ситуаций;Я ускользнул от Содержания.Таким образом, в C # вы должны повысить свой уровень знания языка, и вы должным образом, в соответствии со спецификацией языка C #, работаете над такими проблемами.Рассмотрим решение для обработки большого блока повторяющихся строк кода, который может содержать досадную ошибку выброса:

try
            {
                if (!File.Exists(@"SomeFilePath.xml")) { throw new Exception("XML File Was Not Found!"); }
                string strXML = File.ReadAllText(@"SomeFilePath.xml");
                StringReader sr = new StringReader(strXML);
                DataSet dsXML = new DataSet();
                dsXML.ReadXml(sr);

                Func<string, string, int, string> GetFieldValue = (t, f, x) => (dsXML.Tables[t].Columns.Contains(f) && dsXML.Tables[t].Rows.Count >= x + 1) ? dsXML.Tables[t].Rows[x][f].ToString() : "";

                //-Load data from dynamically created dataset into strings.
                string str1 = GetFieldValue("Table1", "Field1", 0);
                string str2 = GetFieldValue("Table2", "Field2", 0);
                string str3 = GetFieldValue("Table3", "Field3", 0);
                //-And so on.

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            } 

Хотя в блоке try / catch функция lambda проверяет существование каждой таблицыстрока, строка, столбец, извлекаемая из набора данных, который динамически заполняется XML.Это можно проверять построчно, но для этого потребуется много избыточного кода (здесь мы выполняем тот же объем кода, но гораздо меньше написанного кода для поддержки).К сожалению, это можно считать еще одной плохой практикой «функций одной линии».Я нарушаю это правило в случае с лямбдами и анонимными функциями.

Поскольку .NET предлагает так много способов проверить состояние объектов;On Error Resume Next не так важна для экспертов VB, как это было до .NET, но все же приятно иметь ее;особенно когда вы кодируете что-то, что было бы пустой тратой времени, чтобы не писать код быстро и грязно.Вам Java конвертирует в C #;присоединяйтесь к миру Microsoft и перестаньте притворяться, что если 10000 промежуточных программистов на Java и C # говорят это, то это должно быть правдой, потому что если один из высокопоставленных Microsoft Guru (например, любой из тех, кто создал язык VB и .NET) явно противоречитих разработка .NET сама по себе, это ложь, а ты выглядишь глупо.Мне нужны все функциональные возможности, которые я могу получить в C #, VB, F # и любом другом языке, который мне нужно использовать.C # элегантен, но VB более развит, потому что он намного дольше, но они оба делают «То же самое» и используют одни и те же объекты.Изучите их обоих хорошо или, пожалуйста, воздержитесь от комментариев в разговорах сравнения;это тошнотворно для тех из нас, кто был с середины девяностых, используя технологии Microsoft на высоком уровне.

2 голосов
/ 22 марта 2011

Использование "On Error Resume Next" не очень хорошая идея для обработки ошибок (конечно, это мое личное мнение, но, похоже, большинство разработчиков согласны со мной). Как другие парни советовали вам в предыдущих постах, используйте Try...Catch...Finally (будь то VB.NET или C #).

Это очень умный вариант для обработки ошибок, но он также позволит вам ничего не делать с ошибкой (пустой блок catch) :) Я бы посоветовал вам поместить каждую строку кода (которая может вызвать ошибку) в отделите Try...Catch Block, чтобы у вас была возможность делать все, что вы захотите, если произойдет ошибка. Happy Coding, ребята:)

1 голос
/ 18 января 2017

Как сказал @Tim Medora, вы должны приложить усилия, чтобы избежать использования такого подхода при кодировании.Однако в некоторых случаях это полезно, и можно подражать такому поведению.Вот функция и пример ее использования.(Обратите внимание, что некоторые элементы кода были написаны с использованием C # 6)

    /// <summary>
    /// Execute each of the specified action, and if the action is failed, go and executes the next action.
    /// </summary>
    /// <param name="actions">The actions.</param>
    public static void OnErrorResumeNext(params Action[] actions)
    {
        OnErrorResumeNext(actions: actions, returnExceptions: false);
    }

    /// <summary>
    /// Execute each of the specified action, and if the action is failed go and executes the next action.
    /// </summary>
    /// <param name="returnExceptions">if set to <c>true</c> return list of exceptions that were thrown by the actions that were executed.</param>
    /// <param name="putNullWhenNoExceptionIsThrown">if set to <c>true</c> and <paramref name="returnExceptions"/> is also <c>true</c>, put <c>null</c> value in the returned list of exceptions for each action that did not threw an exception.</param>
    /// <param name="actions">The actions.</param>
    /// <returns>List of exceptions that were thrown when executing the actions.</returns>
    /// <remarks>
    /// If you set <paramref name="returnExceptions"/> to <c>true</c>, it is possible to get exception thrown when trying to add exception to the list. 
    /// Note that this exception is not handled!
    /// </remarks>
    public static Exception[] OnErrorResumeNext(bool returnExceptions = false, bool putNullWhenNoExceptionIsThrown = false, params Action[] actions)
    {
        var exceptions = returnExceptions ? new Collections.GenericArrayList<Exception>() : null;
        foreach (var action in actions)
        {
            Exception exp = null;
            try { action.Invoke(); }
            catch (Exception ex) { if(returnExceptions) { exp = ex; } }

            if (exp != null || putNullWhenNoExceptionIsThrown) { exceptions.Add(exp); }
        }
        return exceptions?.ToArray();
    } 

Пример, вместо:

        var a = 19;
        var b = 0;
        var d = 0;
        try { a = a / b; } catch { }
        try { d = a + 5 / b; } catch { }
        try { d = (a + 5) / (b + 1); } catch { }

вы можете:

            var a = 19;
            var b = 0;
            var d = 0;
            OnErrorResumeNext(
                () =>{a = a / b;},
                () =>{d = a + 5 / b;},
                () =>{d = (a + 5) / (b + 1);}
            );
1 голос
/ 02 августа 2014

Мне кажется, что те люди, которые изобрели «On Error Resume Next», действительно что-то имели в виду, когда создавали это.Ответом на ваш вопрос будет «нет», нет ничего эквивалентного этой конструкции в C #.У нас в C # и .Net множество функций, которые так жаждут заботы и внимания, что через некоторое время утомляют, чтобы удовлетворить «исключительное поведение» каждого.Когда почти все может выдать исключение, само слово несколько теряет свой смысл.Вы находитесь внутри итерации, и что вы должны делать, если несколько тысяч из миллионов предметов оказываются исключительными?Резюме Далее может быть одним из удобных ответов.

1 голос
/ 12 августа 2011

Надлежащей заменой .NET для «при возобновлении ошибки далее» является использование методов Try___. В Visual Basic 6.0, чтобы выяснить, существует ли ключ в коллекции, нужно было либо выполнить поиск в коллекции вручную (ужасно медленно), либо попытаться проиндексировать ее и перехватить любую ошибку, которая произошла, если ее там не было. В VB.NET объект Dictionary (который является улучшенной версией старой коллекции) поддерживает метод TryGetValue, который будет указывать, была ли успешной попытка получить значение, не вызывая ошибки, если это не так. Ряд других объектов .NET поддерживают аналогичные функции. Есть несколько методов, которые должны иметь «пробные» эквиваленты, но не имеют (например, Control.BeginInvoke), но их достаточно мало, чтобы обернуть их по отдельности в Try/Catch не слишком обременительно.

...