Подтвердить что ты не робот

Лог поймал исключения из-за пределов метода, в котором они были пойманы

У меня есть метод вроде:

public TResult DoSomethingWithLogging<TResult>(Func<TResult> someAction)
{
    try
    {
        return someAction.Invoke();
    }
    catch (Exception ex)
    {
        LogException(ex)
        throw;
    }

Этот метод используется следующим образом:

var result = DoSomethingWithLogging(() => Foo());

Я также хочу записывать исключения, которые были обнаружены внутри Foo(). Я не могу использовать throw в catch внутри Foo.

Как я могу поймать такие исключения?

Пример:

public static string Foo()
{
    try
    {
        return "Foo";
    }
    catch (Exception)
    {
        // I have to log this exception too without adding anything to Foo
        return "Exception caught";            
    }       
}
4b9b3361

Ответ 1

Вы можете привязываться к событию FirstChanceException. Здесь ваш код изменился, чтобы продемонстрировать это:

using System;
using System.Runtime.ExceptionServices;

public class Program
{
  public static void Main()
  {
      AppDomain.CurrentDomain.FirstChanceException += 
      (object source, FirstChanceExceptionEventArgs e) =>
      {
        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
          AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
      };
    Console.WriteLine("Hello World");
    Console.WriteLine(DoSomethingWithLogging(() => Foo()));
  }

  public static TResult DoSomethingWithLogging<TResult>(Func<TResult> someAction)
  {
    try
    {
      return someAction.Invoke();
    }
    catch (Exception ex)
    {
      Console.WriteLine(ex.Message);
      throw;
    }
  }

  public static string Foo()
  {
    try
    {
      throw new Exception("This will be caught");
      return"Foo";
    }
    catch (Exception) //I have to log this exception too without adding anything too Foo
    {
      return "Exception caught";      
    }    
  }
}

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

Есть также осложнения в многопоточных случаях. В приведенном выше коде демонстрируется, как работает FirstChanceException, но если вы подключили его до вызова и затем отсоединили после того, как он все равно будет запускаться из-за каких-либо исключений из других потоков. Фильтрация этих данных может быть сложной. Вероятно, я начну с рассмотрения взгляда на стек вызовов, но я не уверен, что лучший способ.

Ответ 2

Вы можете сделать это, обратив внимание на AppDomain.FirstChanceException событие:

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

См. Исключение исключений первого шанса в управляемом коде без отладки.

Ответ 3

Я думаю, вы идете по этому пути неправильно. Это очень плохая идея предположить что-то о реализации foo. (Подобно JDM, упомянутому в комментариях, это запах кода, и это приведет вас в неприятности)

Один из способов редизайна вашего подхода - использовать события

class FooClass {

   public event SkippedWorkEventHandler SkippedWork;

   public void Foo() {
      try {
       /* some code */
      } catch (Exception ex) {
         if (SkippedWork != null) {
            /* pass in the relevant data to eventargs */
            SkippedWork(this, EventArgs.Empty)
         }
      }
   }

  public void DoSomethingWithFoo() {
     SkippedWork += new LogSkippedWorkEventHandler 

     try {
        Foo() 
     } catch (Exception ex) {
       /*handle uncaughed exceptions here */
     }

  }
}

Причина этого в том, что со стороны я не буду гарантировать, что я использую try/catch, чтобы обнаружить, что происходит внутри foo. я могу переписать его на простой, если проверить и вернуть, если мой тест не удастся. Результат foo будет таким же, но теперь ваши исключения не регистрируются.

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