practice - handle all exceptions c#




Есть ли разница между «броском» и «броском»? (7)

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

Но мой вопрос отличается тем, что я называю «throw ex» в другом методе обработки ошибок, подобном богу .

public class Program {
    public static void Main(string[] args) {
        try {
            // something
        } catch (Exception ex) {
            HandleException(ex);
        }
    }

    private static void HandleException(Exception ex) {
        if (ex is ThreadAbortException) {
            // ignore then,
            return;
        }
        if (ex is ArgumentOutOfRangeException) { 
            // Log then,
            throw ex;
        }
        if (ex is InvalidOperationException) {
            // Show message then,
            throw ex;
        }
        // and so on.
    }
}

Если try & catch был использован в Main , я бы использовал throw; для восстановления ошибки. Но в приведенном выше упрощенном коде все исключения проходят через HandleException

Выбрасывает throw ex; имеет тот же эффект, что и вызов throw при вызове внутри HandleException ?


(Я опубликовал ранее, и @Marc Gravell исправил меня)

Вот демонстрация разницы:

static void Main(string[] args) {
    try {
        ThrowException1(); // line 19
    } catch (Exception x) {
        Console.WriteLine("Exception 1:");
        Console.WriteLine(x.StackTrace);
    }
    try {
        ThrowException2(); // line 25
    } catch (Exception x) {
        Console.WriteLine("Exception 2:");
        Console.WriteLine(x.StackTrace);
    }
}

private static void ThrowException1() {
    try {
        DivByZero(); // line 34
    } catch {
        throw; // line 36
    }
}
private static void ThrowException2() {
    try {
        DivByZero(); // line 41
    } catch (Exception ex) {
        throw ex; // line 43
    }
}

private static void DivByZero() {
    int x = 0;
    int y = 1 / x; // line 49
}

и вот результат:

Exception 1:
   at UnitTester.Program.DivByZero() in <snip>\Dev\UnitTester\Program.cs:line 49
   at UnitTester.Program.ThrowException1() in <snip>\Dev\UnitTester\Program.cs:line 36
   at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 19

Exception 2:
   at UnitTester.Program.ThrowException2() in <snip>\Dev\UnitTester\Program.cs:line 43
   at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 25

Вы можете видеть, что в Exception 1 трассировка стека возвращается к DivByZero() , тогда как в Exception 2 это не так.

Обратите внимание, что номер строки, показанный в ThrowException1() и ThrowException2() является номером строки оператора throw , а не номером строки вызова DivByZero() , что, вероятно, имеет смысл теперь, когда я думаю об этом немного...

Выход в режиме деблокирования

Исключение 1:

at ConsoleAppBasics.Program.ThrowException1()
at ConsoleAppBasics.Program.Main(String[] args)

Исключение 2:

at ConsoleAppBasics.Program.ThrowException2()
at ConsoleAppBasics.Program.Main(String[] args)

Поддерживает ли исходный стек только в режиме отладки?


Да, есть разница;

  • throw ex сбрасывает трассировку стека (поэтому ваши ошибки будут возникать из HandleException )
  • throw не будет - первоначальный преступник будет сохранен.

Когда вы бросаете ex, это исключенное брошенное становится «оригинальным». Таким образом, все предыдущие трассировки стека не будут.

Если вы делаете бросок, исключение просто идет по линии, и вы получите полную трассировку стека.


Нет, это приведет к тому, что исключение будет иметь другую трассировку стека. Только использование throw без какого-либо объекта исключения в обработчике catch оставит неизменную трассировку стека.

Возможно, вы захотите вернуть логическое выражение из HandleException, будет ли исключение исключено или нет.


Чтобы дать вам другую точку зрения на это, использование throw особенно полезно, если вы предоставляете API клиенту и хотите предоставить подробную информацию о трассировке стека для своей внутренней библиотеки. Используя здесь throw, я получаю трассировку стека в этом случае библиотеки System.IO.File для File.Delete. Если я использую throw ex, то эта информация не будет передана моему обработчику.

static void Main(string[] args) {            
   Method1();            
}

static void Method1() {
    try {
        Method2();
    } catch (Exception ex) {
        Console.WriteLine("Exception in Method1");             
    }
}

static void Method2() {
    try {
        Method3();
    } catch (Exception ex) {
        Console.WriteLine("Exception in Method2");
        Console.WriteLine(ex.TargetSite);
        Console.WriteLine(ex.StackTrace);
        Console.WriteLine(ex.GetType().ToString());
    }
}

static void Method3() {
    Method4();
}

static void Method4() {
    try {
        System.IO.File.Delete("");
    } catch (Exception ex) {
        // Displays entire stack trace into the .NET 
        // or custom library to Method2() where exception handled
        // If you want to be able to get the most verbose stack trace
        // into the internals of the library you're calling
        throw;                
        // throw ex;
        // Display the stack trace from Method4() to Method2() where exception handled
    }
}

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

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

Давайте рассмотрим пример.

Давайте сначала разобраться.

static void Main(string[] args) {
    try {
        M1();
    } catch (Exception ex) {
        Console.WriteLine(" -----------------Stack Trace Hierarchy -----------------");
        Console.WriteLine(ex.StackTrace.ToString());
        Console.WriteLine(" ---------------- Method Name / Target Site -------------- ");
        Console.WriteLine(ex.TargetSite.ToString());
    }
    Console.ReadKey();
}

static void M1() {
    try {
        M2();
    } catch (Exception ex) {
        throw;
    };
}

static void M2() {
    throw new DivideByZeroException();
}

вывод выше приведен ниже.

показывает полную иерархию и имя метода, где на самом деле выбрано исключение. Это M2 -> M2. наряду с номерами строк

Во-вторых .. давайте поймем, бросьте экс. Просто замените throw с помощью throw ex в блоке catch метода M2. как показано ниже.

вывод кода throw ex, как показано ниже.

Вы можете увидеть разницу в выходе. Throw ex просто игнорирует всю предыдущую иерархию и сбрасывает трассировку стека с помощью линии / метода, где записывается throw ex.


int a = 0;
try {
    int x = 4;
    int y ;
    try {
        y = x / a;
    } catch (Exception e) {
        Console.WriteLine("inner ex");
        //throw;   // Line 1
        //throw e;   // Line 2
        //throw new Exception("devide by 0");  // Line 3
    }
} catch (Exception ex) {
    Console.WriteLine(ex);
    throw ex;
}
  1. если все строки 1, 2 и 3 прокомментированы - вывод - внутренний ex

  2. если все строки 2 и 3 прокомментированы - Output - internal ex System.DevideByZeroException: {«Попытка деления на ноль».} ---------

  3. если все строки 1 и 2 прокомментированы - вывод - внутренний ex System.Exception: devide by 0 ----

  4. если все строки 1 и 3 прокомментированы - Output - internal ex System.DevideByZeroException: {«Попытка деления на ноль».} ---------

и StackTrace будет сброшен в случае throw ex;





exception-handling