获取引发exception的方法名称

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

  • 如何获取导致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()方法发生exception。 之后我将site.Name的值作为WinIOError而不是FillCombo

我尝试了另一种方法GetExecutingMethodName() ,由Chris Gessler在如何获取导致exception问题的方法的名称中回答。 所以我尝试使用GetExecutingMethodName()方法发送导致exception的方法名称

 Log(ex.ToString(), GetExecutingMethodName()); 

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

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

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

 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; 

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

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

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

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

  1. 看来你已经在声明了Click事件处理程序的同一个类中声明了该方法。 这意味着忽略了事件处理程序方法,因此您获得该方法的调用者,即Control.OnClick()方法(即实际引发事件的方法)。

坦率地说,我发现特定的答案很奇怪,因为.NET已经提供了一个API来检索当前正在执行的方法的MethodInfo : MethodBase.GetCurrentMethod 。 这比克里斯盖斯勒写的代码更可靠。

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

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

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

 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的方法的实际名称。 这是记录整个Exception对象的另一个原因通常更有用; 环境越多,你就越有可能重建发生的事情。

试试这个:

 var methodFullName = exception.TargetSite.ReflectedType.FullName