Обнаружение при работе внутри блока захвата

Как определить, когда исполняемый в данный момент код вызывается из блока 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);
}
Другие вопросы по тегам