Какую наилучшую практику следует учитывать при отлове исключений и повторном их отбрасывании? Я хочу убедиться, что Exception
объект InnerException
и трассировка стека сохранены. Есть ли разница между следующими блоками кода в способе их обработки?
try
{
//some code
}
catch (Exception ex)
{
throw ex;
}
Vs:
try
{
//some code
}
catch
{
throw;
}
источник
ExceptionDispatchInfo.Capture(ex).Throw(); throw;
в .NET +4.5 stackoverflow.com/questions/57383/…Если вы сгенерируете новое исключение с начальным исключением, вы также сохраните начальную трассировку стека.
источник
AggregateException
следует использовать только для исключений над агрегированными операциями. Например, он брошен вParallelEnumerable
иTask
классы CLR. Использование должно, вероятно, следовать этому примеру.На самом деле, есть некоторые ситуации,
throw
когда информация не будет сохранять информацию StackTrace. Например, в коде ниже:StackTrace будет указывать, что строка 54 вызвала исключение, хотя оно было поднято в строке 47.
В ситуациях, подобных описанной выше, существует два варианта сохранения исходного StackTrace:
Вызов Exception.InternalPreserveStackTrace
Поскольку это частный метод, его необходимо вызывать с помощью отражения:
У меня есть недостаток в том, что я полагаюсь на закрытый метод для сохранения информации StackTrace. Это может быть изменено в будущих версиях .NET Framework. Пример кода выше и предлагаемое решение ниже были извлечены из блога Fabrice MARGUERIE .
Вызов Exception.SetObjectData
Методика, предложенная ниже, была предложена Антоном Тихым в ответ на In C #, как я могу сбросить InnerException, не теряя вопрос трассировки стека .
Несмотря на то, что он имеет преимущество полагаться только на общедоступные методы, он также зависит от следующего конструктора исключений (который некоторые реализации, разработанные сторонними разработчиками, не реализуют):
В моей ситуации мне пришлось выбрать первый подход, потому что исключения, вызванные сторонней библиотекой, которую я использовал, не реализовали этот конструктор.
источник
Когда вы
throw ex
, вы, по сути, генерируете новое исключение и пропускаете исходную информацию трассировки стека.throw
является предпочтительным методом.источник
Правило большого пальца состоит в том, чтобы избегать Поймать и Бросить основной
Exception
объект. Это заставляет вас быть немного умнее с исключениями; другими словами, у вас должен быть явный улов для a,SqlException
чтобы ваш код обработки не делал что-то не так с aNullReferenceException
.В реальном мире, однако, перехват и запись базового исключения также является хорошей практикой, но не забудьте пройтись по всему этому, чтобы получить все, что
InnerExceptions
оно может иметь.источник
Вы всегда должны использовать «бросить»; отбросить исключения в .NET,
Ссылайтесь на это, http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx
В основном MSIL (CIL) имеет две инструкции - «throw» и «rethrow»:
По сути, я вижу причину, по которой «throw ex» переопределяет трассировку стека.
источник
throw ex;
ее свергнут - в Java это так! Но вы должны включить эту информацию сюда, чтобы получить ответ на вопрос. (Хотя я все ещеExceptionDispatchInfo.Capture
догоняю ответ от jeuoekdcwzfwccu .)Никто не объяснил разницу между
ExceptionDispatchInfo.Capture( ex ).Throw()
и равнинойthrow
, так что вот она. Однако некоторые люди заметили проблему сthrow
.Полный способ отбросить перехваченное исключение - использовать
ExceptionDispatchInfo.Capture( ex ).Throw()
(доступно только в .Net 4.5).Ниже приведены случаи, необходимые для проверки этого:
1.
2.
3.
4.
Случай 1 и случай 2 дадут вам трассировку стека, где номер строки исходного кода для
CallingMethod
метода является номеромthrow new Exception( "TEST" )
строки строки.Однако случай 3 даст вам трассировку стека, где номер строки исходного кода для
CallingMethod
метода является номером строкиthrow
вызова. Это означает, что еслиthrow new Exception( "TEST" )
строка окружена другими операциями, вы не знаете, по какому номеру строки было выдано исключение.Случай 4 аналогичен случаю 2, потому что номер строки исходного исключения сохраняется, но не является реальным перебросом, потому что он меняет тип исходного исключения.
источник
throw ex;
и это лучший ответ из всех.Несколько человек на самом деле упустили очень важный момент - «throw» и «throw ex» могут делать одно и то же, но они не дают вам важную часть информации, которая является той чертой, где произошло исключение.
Рассмотрим следующий код:
Когда вы делаете 'throw' или 'throw ex', вы получаете трассировку стека, но строка # будет # 22, так что вы не сможете выяснить, какая именно строка выдает исключение (если у вас только 1 или несколько строки кода в блоке try). Чтобы получить ожидаемую строку № 17 в вашем исключении, вам нужно сгенерировать новое исключение с исходной трассировкой стека исключений.
источник
Вы также можете использовать:
И любые выданные исключения будут пузыриться до следующего уровня, который обрабатывает их.
источник
Я бы определенно использовал:
Это сохранит ваш стек.
источник
throw
; например, вы можете очистить одноразовое устройство (когда вы вызываете его ТОЛЬКО при ошибке), а затем выбросить исключение.К вашему сведению, я только что проверил это и трассировку стека сообщил 'throw;' не совсем корректная трассировка стека. Пример:
Трассировка стека правильно указывает на источник исключения (сообщенный номер строки), но номер строки, сообщенный для foo (), является строкой броска; оператор, следовательно, вы не можете сказать, какой из вызовов bar () вызвал исключение.
источник