【问题标题】:Get calling method which caused exception in the catch获取导致捕获异常的调用方法
【发布时间】:2012-09-04 13:40:06
【问题描述】:

我在 Windows 窗体的主入口点处理*异常。我想访问在我的处理程序中导致异常的调用方法/程序集。我有一种感觉,我将不得不为此使用跟踪,但我不确定在哪里。

Module Program
  Sub Main()
    Try
      AddHandler AppDomain.CurrentDomain.UnhandledException, Function(sender, e) ExceptionHandler.Handle(sender, DirectCast(e.ExceptionObject, Exception))
      AddHandler Application.ThreadException, Function(sender, e) ExceptionHandler.Handle(sender, e.Exception)
      Application.Run(ApplicationBase)
    Catch ex As Exception
      MessageBox.Show("Handled Exception")
    End Try
  End Sub
End Module

Public Class ApplicationBase
  Public Sub MethodA()
    'Causes an exception
    File.ReadAllLines("")
  End Sub
End Class

Public Class ExceptionHandler

  Public Shared Function Handle(sender As Object, e As Exception)
    Dim t As Type = sender.GetType()
    'Retrieve the calling method here?
    Dim callingMethod = "MethodA"
    Return True
  End Function

End Class

作为发送者通过的对象是一个线程,我试图查看这是否是调用导致异常的程序集/对象类型。

我的问题是,如果可能的话,我如何从“句柄”方法中获取方法名称/信息并推送对象名称/程序集?

编辑:

尽管 e.ToString() 将显示方法名称 - 我正在寻找对方法信息列表/程序集/引发异常的类型(如反射)的访问,然后我可以获得 .DLL 的版本号等等 - 我可能在这里做梦,但我想知道这是否可能?

编辑 2:

我尝试了 e.TargetSite,它对于 MethodA() 异常返回 File.ReadAllLines() 的方法信息我正在寻找导致异常的 Class 方法,因此方法信息将是 MethodA - 虽然这更接近比我想象的要多。

【问题讨论】:

    标签: .net vb.net


    【解决方案1】:

    如果您想知道哪个方法引发了异常,您可以使用Exception.TargetSite 属性;它返回一个MethodBase

    如果引发此异常的方法不可用并且堆栈跟踪不是空引用(在 Visual Basic 中为 Nothing),TargetSite 从堆栈跟踪中获取该方法。如果堆栈跟踪是一个空引用,TargetSite 也会返回一个空引用。

    如果您想在异常发生时遍历堆栈跟踪以查找代码中的方法(而不是库代码中的方法),您必须自己分析堆栈跟踪。

    你可以获得异常的堆栈跟踪:

    Dim stackTrace = new StackTrace(ex)
    

    可以通过索引获取单个栈帧:

    Dim stackFrame = stackTrace.GetFrame(index)
    

    可以从栈帧中获取信息:

    Dim method = stackFrame.GetMethod()
    

    然后,您必须提出一种算法,从上到下遍历堆栈跟踪,寻找满足您的标准的第一个帧作为您要报告的堆栈帧。这是一个非常简单的算法,可以找到执行程序集中的第一帧。

    Dim stackTrace = new StackTrace(ex)
    Dim i As Integer
    For i = 0 To stackTrace.FrameCount - 1
      Dim stackFrame = stackTrace.GetFrame(i)
      Dim method = stackFrame.GetMethod()
      If (method.DeclaringType.Assembly = Assembly.GetExecutingAssembly()) Then
        ' Found the method - do something and exit the loop
        Exit For
      End If
    Next i
    

    【讨论】:

    • 如果将stackFrame的声明改为Dim stackFrame As System.Diagnostics.Stackframe,则可以获得stackFrame.GetFileLineNumber(),但这可能返回0。
    【解决方案2】:

    e.ToString() 将返回包括堆栈跟踪在内的完整详细信息。堆栈跟踪包括所有方法名称。

    【讨论】:

    • 哇,这是漫长的一天,不知道为什么我没有意识到这一点。但是,这只是一般的异常字符串,我想要方法信息或单个方法名称。无论如何我可以将类型作为对象或调用程序集取出,然后我可以使用反射/
    • 我相信,e.TargetSite 会为您提供所需的内容。
    • +1 让我意识到 - 但我想要的一个小例子是在处理程序中有一个 MethodInfo 变量(Dim info as MethodInfo),然后将其设置为导致异常的方法(方法 A)。如果可能的话,然后是程序集/类型。
    • 刚刚尝试过 e.TargetSite 它给了我低于类方法的级别 - File.ReadAllLines() 所以显然这是导致异常的方法而不是导致异常的类中的方法(如果愿意,可以寻找目标网站的父网站)。再次感谢您的回答:)
    • @LukeHennerley:您的代码不会总是只比引发异常的方法高一级。您的代码和引发异常的代码之间可能有多个堆栈帧,或者如果是您自己的代码引发了异常,则两者之间没有堆栈帧。
    【解决方案3】:

    [已编辑]

    看看How to format Exception's stack trace in C#?。使用接受异常的System.Diagnostics.StackTrace的构造函数。

    【讨论】:

    • 我应该更具体。您构造 System.Diagnostics.StackTrace 对象并将异常传递给构造函数。我将编辑我的答案。
    最近更新 更多