Я скучаю по Visual Basic "При ошибке возобновить дальше" в C#. Как я должен обрабатывать ошибки сейчас?

В Visual Basic я написал только On Error Resume Next В голове моей программы и ошибки были подавлены во всем проекте.

Здесь, в C#, я очень скучаю по этой функции. Обычный try-catch обработка каждой отдельной процедуры не только очень трудоемка, но и приводит к нежелательным последствиям. Если обнаружена ошибка, даже если она обработана, код не продолжается с того места, где она возникла. С On Error Resume Nextкод продолжался с точки ошибки, пропуская только вызов функции, вызвавший ошибку.

Я еще не глубоко связан с C#, но, возможно, в C# существует лучшая обработка ошибок, чем примитив try-catch,

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

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

Мое решение, которое я нашел, чтобы решить некоторые из моих проблем:

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    [STAThread]
    static void Main()
    {
      Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); //setup global error handler
      Application.Run(new Form1());
    }

    private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    {   
            MessageBox.Show("Unhandled exception: " + e.Exception.ToString()); //get all error information with line and procedure call
            Environment.Exit(e.Exception.GetHashCode()); //return the error number to the system and exit the application
    }

    private void button1_Click(object sender, EventArgs e)
    {
        string s = ""; s.Substring(1, 5); //Produce an error
    }

   }

6 ответов

Решение

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

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

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

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

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

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

Каким-то образом C# всегда выдает много ошибок при выполнении, это типично для языка.

Нет, это просто говорит о том, что ты делаешь это неправильно.

Нет.

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

  1. написать код, который не содержит ошибок... если что-то не происходит, это на самом деле проблема. Это может включать проверку ваших предположений, прежде чем делать что-то; отлично: сделай это
  2. только ловить проблемы, которые вы ожидали; проглатывание всех ошибок просто требует больших проблем

Как уже отмечал Джон, на самом деле довольно редко требуется повсеместная обработка исключений. Обычно вы просто позволяете исключению всплывать до вызывающего абонента, потому что что- то плохое только что произошло. И когда у меня есть try чаще try / finally (не try / catch) - с using а также lock (и т. д.) для особых случаев.

Нет, ты не можешь. Это невозможно в C# (и не должно быть на любом другом языке).

Истинное использование для этого в VB было сделать обработку ошибок в некоторой части кода, так же, как try / catch, Вы включаете его, проверьте с Err.Number <> 0, сделайте свою работу и восстановите поток ошибок с On Error GoTo 0 или перенаправить на метку, которая следует по другому пути, чтобы обработать ошибку или продолжить выполнение On Error GoTo someErrorCase:,

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

Доверьтесь мне. Я был программистом на VB, и это было поучительно, когда я перестал читать лучшие практики.

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

Кроме того, исключения C# очень полезны и содержат всю необходимую информацию. Если у вас нет проблемы с самим исключением, просто откройте его и посмотрите на его внутреннее исключение (я ловлю меня на том, что всегда ищу внутренние исключения при разработке для веб, так как весь код находится на более высоком уровне).

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

Вы неправильно использовали эту функцию VB, и вам так повезло, что вы не можете использовать ее в C# таким образом.

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

Итак, если вы думаете, что вам нужно больше обрабатывать ошибки в C#, вы делали слишком мало обработки ошибок раньше.

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

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

Проблема с "On Error Resume Next" в VB.NET заключается в том, что он загружает объект err в каждой строке исполняемого кода и, следовательно, медленнее, чем try / catch.

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

        Dim strXML As String = File.ReadAllText("SomeNonExistentFileCausingAnErrorCondition.xml")
        If String.IsNullOrEmpty(strXML) Then
            strXML = strSomeOtherValidXmlThatIUseWhenTheFileIsEmpty
        End If
        Dim srXmL As StringReader = New StringReader(strXML)
        Dim dsXML As DataSet = New DataSet()
        dsXML.ReadXml(srXmL)
        If Err.Number <> 0 Then
            MsgBox(Err.Number & Space(1) & Err.Description)
            Exit Sub
        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()

В приведенном выше коде необходимо было обработать только одно возможное состояние ошибки; даже при загрузке файла произошла ошибка. При ошибке Resume Next фактически позволил мне возобновить работу, как предполагалось, что позволило мне проверить условие строки и использовать мою альтернативную строку (я хорошо знаю, что мог бы также проверить наличие файла и избежать ошибки файла, но если это был хороший файл, в котором ничего не было, strXML был бы пустой строкой). Ошибка, которая была критической для остальной части кода, была обработана, и метод был закрыт, потому что загруженный набор данных имел первостепенное значение для остальной части обработки за его пределами (обработка, которая могла бы выполняться, игнорируя любые ошибки, если это необходимо). Ошибка файла могла быть проигнорирована, поскольку я проигнорировал это, или я мог проверить условие ошибки и зарегистрировать это.

Требуется разработка 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 лямбда-функция проверяет существование каждой таблицы, строки, комбинации столбцов, которые извлекаются из набора данных, динамически заполненного xml. Это можно проверять построчно, но для этого потребуется много лишнего кода (здесь у нас столько же исполняемого кода, но гораздо меньше написанного кода для поддержки). К сожалению, это можно считать еще одной плохой практикой "функций одной линии". Я нарушаю это правило в случае с лямбдами и анонимными функциями.

Поскольку.NET предлагает так много способов проверить состояние объектов; On Error Resume Next не так важна для экспертов VB, как это было до.NET, но все же приятно иметь ее; особенно когда вы кодируете что-то, что было бы пустой тратой времени, чтобы не писать код быстро и грязно. Никто из тех, кто когда-либо использовал VB на экспертном уровне, никогда не будет утверждать, что On Error Resume Next (встроенная обработка ошибок) - худшая функция, когда-либо добавленная в язык. Тем не менее, он широко использовался новичками.

Другие вопросы по тегам