记录从捕获它们的方法之外捕获异常

时间:2015-11-24 12:02:45

标签: c# exception lambda

我的方法如下:

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";            
    }       
}

3 个答案:

答案 0 :(得分:17)

您可以绑定到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如何工作,但是如果你在调用之前附加了,然后在它之后分离,它仍会被其他线程上的任何异常触发。过滤掉那些可能会很棘手。我可能首先考虑查看调用堆栈,但我不确定这是最好的方法。

答案 1 :(得分:4)

您可以通过处理AppDomain.FirstChanceException event

来实现
  

在运行时在应用程序域中搜索调用堆栈中的异常处理程序之前,在托管代码中抛出异常时发生。

请参阅Catching First Chance Exceptions in Managed Code without being debugged

答案 2 :(得分:2)

我认为你的做法是错误的。假设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中发生的事情。如果我的测试失败,我可能会将其重写为简单的if check并返回。 foo的结果是相同的,除非现在没有记录您的异常。

通过公开活动,您可以允许任何对某些事物感兴趣的人(基于您的评论的跳过的行)对其做出反应。并且你签了一份合同,说你将荣幸/举起这个活动。