获取引发异常的方法名称

时间:2015-01-17 07:29:58

标签: c# exception

我知道。类似的问题已经提出过了。

但我还没有得到确切的解决方案。

我有一个按钮点击事件,其中我有一个方法FillCombo()

按钮点击事件

private void button1_Click(object sender, EventArgs e)
{
      try
      {
          cmbTemplates.Items.Clear();
          lstFiles.Clear();
          FillCombo();                
      }
      catch (Exception ex)
      {
           MethodBase site = ex.TargetSite;
           Log(ex.ToString(), site == null ? null : site.Name);                
      }
}

当我调试时,我发现异常发生在FillCombo()方法中。之后,我将site.Name的值设为WinIOError而不是FillCombo

我尝试了另一种方法GetExecutingMethodName()How to get the name of the method that caused the exception问题中 Chris Gessler 回答了这个问题。所以我尝试使用GetExecutingMethodName()方法

发送导致异常的方法名称
Log(ex.ToString(), GetExecutingMethodName());

但我的结果为System.Windows.Forms.Control.OnClick而不是FillCombo

如何获取导致异常的方法的实际名称?

3 个答案:

答案 0 :(得分:14)

.net支持从异常中获取堆栈跟踪信息。您可以通过检查第一帧(原点)来过滤掉方法(及其名称)。

new StackTrace(ex).GetFrame(0).GetMethod().Name

这可能会给你与targetite(win io)完全相同,但你可以检查第一个用户代码的堆栈跟踪,或类型中的第一帧,或者你需要的任何一个。

例如,在当前程序集中获取罪魁祸首的名称:

var s = new StackTrace(ex);
var thisasm = Assembly.GetExecutingAssembly();                
var methodname = s.GetFrames().Select(f => f.GetMethod()).First(m => m.Module.Assembly == thisasm).Name;

答案 1 :(得分:8)

了解“抛出异常的方法”的含义非常重要。发生异常时,会有一个实际执行的特定方法。只是因为在异常之前的某个时刻,你调用了自己的FillCombo()方法,这并不意味着抛出异常的方法。

然而,FillCombo()方法(在你关心的情况下)将在堆栈跟踪中。这就是为什么记录整个堆栈跟踪很有用的原因。实际上,我通常只记录整个Exception对象(即ex.ToString(),或者只是将异常对象传递给string.Format()或类似的,它会为您调用ToString()。这将包括异常类型,消息,整个堆栈跟踪,甚至内部异常信息(如果存在)。


对于GetExecutingMethodName()方法,你从另一个问题得到的代码并不是真正有用的恕我直言。你会注意到它真正做的是爬行当前执行位置的堆栈跟踪,寻找在GetExecutingMethodName()之外的类型中声明的第一个方法宣布了。

出于两个原因,这对你的目的是错误的:

  1. 看来你已经在声明了Click事件处理程序的同一个类中声明了该方法。这意味着忽略了事件处理程序方法,因此您获得该方法的调用者,即Control.OnClick()方法(即实际引发事件的方法)。
  2. 坦率地说,我发现这个特别的答案很奇怪,因为.NET已经提供了一个API来检索当前正在执行的方法的MethodInfoMethodBase.GetCurrentMethod。这比Chris Gessler编写的代码更可靠。

    1. 更有问题的是,您没有机会在抛出异常时调用此方法!充其量(即使你处理声明帮助方法的位置的问题),所有调用它的人都会告诉你,你在button1_Click()方法中。但是您已经知道了,因为您编写的用于处理异常的代码是在该方法中。

    2. 如果您想知道在异常发生之前调用的当前正在执行的方法中的方法名称,可以将这两种技术结合起来:获取当前正在执行的方法的名称,然后将其传递给同时采用这两种方法的方法和来自Exception对象的堆栈跟踪字符串,并让该方法解析堆栈跟踪字符串,以便在跟踪中当前正在执行的方法之前找到该帧。

      这有点痛苦,但可以做到。这是一个示例(简单的概念验证控制台程序):

      static void Main(string[] args)
      {
          try
          {
              CallForException();
          }
          catch (Exception e)
          {
              Console.WriteLine("Exception occurred calling {0} method", GetCallForExceptionThisMethod(MethodBase.GetCurrentMethod(), e));
          }
      }
      
      private static string GetCallForExceptionThisMethod(MethodBase methodBase, Exception e)
      {
          StackTrace trace = new StackTrace(e);
          StackFrame previousFrame = null;
      
          foreach (StackFrame frame in trace.GetFrames())
          {
              if (frame.GetMethod() == methodBase)
              {
                  break;
              }
      
              previousFrame = frame;
          }
      
          return previousFrame != null ? previousFrame.GetMethod().Name : null;
      }
      
      private static void CallForException()
      {
          DoActualException();
      }
      
      private static void DoActualException()
      {
          throw new NotImplementedException();
      }
      

      最后,请记住,由于方法内联和其他优化,即使是完整的堆栈跟踪也可能存在一些不规则性,包括甚至没有抛出异常的方法的实际名称。这是记录整个Exception对象的另一个原因通常更有用;环境越多,你就越有可能重建发生的事情。

答案 2 :(得分:1)

试试这个:

var methodFullName = exception.TargetSite.ReflectedType.FullName