Обнаружение при работе внутри блока захвата
Как определить, когда исполняемый в данный момент код вызывается из блока catch?
void SomeFunction()
{
// how do I detect whether I am being called from within a catch block?
}
РЕДАКТИРОВАТЬ:
Для тех, кто спрашивает, я хотел реализовать класс, подобный этому, не говоря уже о логике всплывающей ошибки: При написании этого примера кода я получаю ошибку компилятора "Оператор throw без аргументов не разрешен вне предложения catch", поэтому это все равно разрушает мою идею.
public class ErrorManager {
public void OnException(Exception ex) {
LogException(ex);
if (IsInsideCatchBlockAlready()) {
// don't destroy the stack trace,
// but do make sure the error gets bubbled up
// through the hierarchy of components
throw;
} else {
// throw the error to make it bubble up
// through the hierarchy of components
throw ex;
}
}
void LogException(Exception ex) {
// Log the exception
}
bool IsInsideCatchBlockAlready() {
// How do I implement this?
}
}
6 ответов
Вы не Нет никакого способа узнать, будет ли, если вы сгенерируете исключение, оно будет перехвачено или остановит программу. Вы потенциально можете сделать предположение во время компиляции с помощью инструмента анализа кода, но это не будет вариантом, пока код работает.
Нет, это невозможно сделать.
Может быть какой-то хитрый способ анализа сгенерированного (IL) кода, но я уверен, что вы этого не хотите.
Это IL из стандартного консольного приложения, улавливающего исключение:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 34 (0x22)
.maxstack 1
IL_0000: nop
.try
{
IL_0001: nop
IL_0002: ldstr "OK"
IL_0007: call void [mscorlib]System.Console::WriteLine(string)
IL_000c: nop
IL_000d: nop
IL_000e: leave.s IL_0020
} // end .try
catch [mscorlib]System.Exception
{
IL_0010: pop
IL_0011: nop
IL_0012: ldstr "Err"
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: nop
IL_001d: nop
IL_001e: leave.s IL_0020
} // end handler
IL_0020: nop
IL_0021: ret
} // end of method Program::Main
Если вы можете проанализировать, что ваш текущий код (скажем, в "OK"
) находится внутри этого блока, вы можете извлечь try ... catch
блок. Это, конечно, не учитывает вызов других методов.
Это также звучит как нелепое решение проблемы, с которой вы столкнулись, поэтому, прежде чем заняться чем-то, что вам не нужно, подумайте, действительно ли вы хотите это сделать.
Исключения CLR в Windows - это просто еще одна SEH. Прочитайте классику: Ускоренный курс по глубине структурированной обработки исключений Win32™. Очевидно, что можно обнаружить, что ваш код выполняется во время обработчика SEH, так как ExceptionNestedException
должен быть обнаружен. TEB содержит все необходимое, если вы являетесь операционной системой или отладчиком и знаете, как его интерпретировать.
Для вас я настоятельно рекомендую отступить и пойти по задокументированному пути. При необходимости оберните вход в блоки try/catch, чтобы избежать утечки исключений из кода, который требуется не генерировать. Убедитесь, что вы справляетесь ThreadAbortException
правильно, так как это особенное. Крюк в Application.UnhandledException
, Application.ThreadException
и / или AppDomain.UnhandledException
при необходимости, с надлежащей регистрацией и отчетами об ошибках.
Вы задали неправильный вопрос, мой друг!
Большинство фреймворков допускают обработку необработанных исключений определенным методом. WPF, C# webforms, asp, все они имеют подпрограмму "обработки необработанных исключений", которую можно подключить на уровне приложения.
Например, обычные приложения на формах C# используют:
Application.ThreadException += new ThreadExceptionEventHandler(MyCommonExceptionHandlingMethod)
private static void MyCommonExceptionHandlingMethod(object sender, ThreadExceptionEventArgs t)
{
//Exception handling...
}
Так что вам просто нужно объявить свой класс управления исключениями, а затем подключить класс к обработке исключений, например:
Application.ThreadException += new ThreadExceptionEventHandler(TellMyClass)
private static void TellMyClass(object sender, ThreadExceptionEventArgs t)
{
ExceptionManager.HandleException(sender, t);
}
Тем не менее, шаблон, который я использовал:
public static class UnhandledExceptionManager {
Logger _logger;
public static void RegisterToHandleFormsException(){
_logger = new Logger();
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += OnThreadException;
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
}
public static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e){
HandleException((Exception)e.ExceptionObject);
}
private static void HandleException(Exception exception, [CallerMemberName] string methodName = "")
{
try
{
_logger.Error(methodName, exception);
}
catch (Exception e)
{
Debug.WriteLine("({0}) {1}", methodName, e);
}
}
}
Который используется в Program.cs:
public static void Main(){
UnhandledExceptionManager.RegisterToHandleFormsException();
//etc
}
Как указано в других ответах, вы не можете. Вы можете подделать его, передав параметр методу, но это кажется запахом кода.
Вы всегда можете сделать это простым способом:
void SomeFunction(bool isCalledFromCatch)
{
// how do I detect whether I am being called from within a catch block?
}
try
{
}
catch(...)
{
SomeFunction(true);
}