puja11191 Ответов: 2

Разница между броском и броском ex в C#


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace throwMyDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            RaiseExcption r = new RaiseExcption();
            try
            {
               r.Without();
            }
            catch(MyException ex1)
            {
                Console.WriteLine(ex1.Message);
                Console.WriteLine(ex1.StackTrace);
                Console.Read();
            }
            try
            {

             
                r.With();
            }
            catch (MyException ex2)
            {
                Console.WriteLine(ex2.Message);
                Console.WriteLine(ex2.StackTrace);
                Console.Read();
                Console.Read();
            }
        }
    }
    class MyException : Exception
    {
        public MyException():base()
    {
    }

    }
    class RaiseExcption
    {
        public void Without()
        {
            try
            {
                throw new MyException();
            }
            catch (MyException me)
            {
                throw;
            }
        }
        public void With()
        {
            try
            {
                throw new MyException();
            }
            catch (MyException me)
            {
                throw me;
            }
        }
    }
}

Я написал этот код, чтобы проверить разницу между throw и throw ex, но, к сожалению, он не работает. Я имею в виду, что трассировка стека как для with, так и для without указывает местоположение ошибки как throw statment, а не указывает точное местоположение ошибки, где было выброшено исключение. throw new MyException() - Кто-нибудь может мне в этом помочь? Заранее спасибо

Alan N

Я исправил форматирование кода, и теперь вам нужно отредактировать вопрос и рассказать нам, что означает "не работает". Каковы были ожидаемые и фактические результаты программы?

puja11191

Привет, Алан, спасибо за форматирование кода. На самом деле, когда я запускаю код, трассировка стека как с (), так и без() показывает один и тот же результат. Но, как я и ожидал, когда мы используем throw, он должен показывать точную точку в приложении, где произошла ошибка. Пожалуйста, свяжитесь со мной для получения дополнительных разъяснений по этому вопросу. Заранее спасибо

[no name]

Редактировать: добавлен код блока

2 Ответов

Рейтинг:
14

OriginalGriff

Когда вы используете бросок с пустым параметром, вы повторно бросаете последнее исключение. Когда вы создаете существующее исключение, вы создаете новое исключение.

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


Abhinav S

5. Отличный ответ.

[no name]

мои 5!

puja11191

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

Monjurul Habib

мои 5!

Рейтинг:
12

Alan N

Я не знал об этом поведении и нахожу его весьма удивительным. Это, конечно, выглядит так, как будто throw ведет себя неправильно, но это не так, и мы можем увидеть это более ясно, если мы переместим источник исключения и catch-retrow в разные методы.

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

Вот простая программа, которая демонстрирует, как номера строк могут изменяться внутри кадра стека.

class Program {
  static void Main(string[] args) {
    Console.BufferWidth = 160;

    Console.WriteLine("Indirect call of BadMethod with no rethrows");
    Console.WriteLine("*******************************************");
    try {
#line 100
      PassThrough();
#line default
    } catch (Exception e) {
      Console.WriteLine(e);
    }
    Console.WriteLine();

    Console.WriteLine("Indirect call of BadMethod with rethrow");
    Console.WriteLine("***************************************");
    try {
#line 200
      WithRethrow();
#line default
    } catch (Exception e) {
      Console.WriteLine(e);
    }
    Console.WriteLine();
    Console.Read();
  }

  public static void PassThrough() {
#line 1000
    BadMethod();
#line default
  }

  public static void WithRethrow() {
    try {
#line 2000
      BadMethod();
    } catch (Exception e) {
      Console.WriteLine(e);
      throw;
    }
#line default
  }

  public static void BadMethod() {
#line 3000
    throw new Exception("\"MSG: Good method gone bad\"");
#line default
  }
}

Странное дело #line директивы изменяют номера строк, сохраненные в отладочной информации, и дают нам простые номера в трассировках стека. Это было сделано для того, чтобы облегчить обсуждение результатов.

Есть два случая, и в обоих мы называем исключение, бросающее BadMethod() через посредника, либо PassThrough (), который ничего не делает, либо WithRethrow (), который делает то, что предполагает название.

Indirect call of BadMethod with no rethrows
*******************************************
System.Exception: "MSG: Good method gone bad"
   at BadMethod()          line 3000
   at PassThrough()        line 1000
   at Main(String[] args)  line 100

Indirect call of BadMethod with rethrow
***************************************
System.Exception: "MSG: Good method gone bad"
   at BadMethod()          line 3000
   at WithRethrow()        line 2000
System.Exception: "MSG: Good method gone bad"
   at BadMethod()          line 3000
   at WithRethrow()        line 2003
   at Main(String[] args)  line 200


Если вы можете представить себе исключение, проходящее через метод в поиске соответствующего блока catch, то в PassThrough() исключение входит и выходит с тем же номером строки (1000), и об этом сообщается в кадре стека.

В методе WithRethrow() исключение входит в строку 2000, но покидает ее в строке 2003 после перехвата и повторной обработки. Сравнение трассировки стека, полученной в WithRethrow (), с трассировкой из Main() ясно показывает изменение сообщаемого номера строки.

Это в точности аналогично ситуации, которую вы первоначально описали, т. е.
public void WTFMethod() {
  try {
    throw new Exception();
  } catch {
    throw;
  }
}


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

Алан.