在.net Exception中如何获取带有参数值的堆栈跟踪

Cae*_*nog 39 .net c# exception

我试图在.net(c#)中添加一个未处理的异常处理程序,该处理程序对于'user'应该尽可能有用.最终用户大多是程序员,所以他们只需要暗示他们操纵错误的对象.

当应用程序崩溃时,我正在开发类似于Windows XP错误报告的窗口,但是尽可能多地提供关于抛出的异常的中间信息.

虽然堆栈跟踪使我(因为我有源代码)能够查明问题的根源,但是用户没有它,因此它们在没有进一步信息的情况下丢失.不用说我必须花很多时间来支持这个工具.

有一些系统异常,如Dictionary集合抛出的KeyNotFoundException,它真的让我感到烦恼,因为它们没有在消息中包含未找到的密钥.我可以使用大量的try catch块来填充我的代码,但它相当激进并且需要维护更多的代码,更不用说更多的字符串必须最终被本地化.

最后一个问题:有没有办法获得(在运行时)调用堆栈跟踪中每个函数的参数值?仅这一点就可以解决90%的支持电话.

use*_*375 7

我不认为System.Diagnostics.StackFrame提供参数信息(方法签名除外).

您可以通过AOP跟踪日志记录来检测麻烦的调用,甚至可以使用其异常拦截功能有条件地记录而不必乱丢您的代码.浏览http://www.postsharp.org/.


Ste*_*gan 6

同样,我没有找到任何在运行时自动派生参数的东西.相反,我使用Visual Studio加载项生成明确打包参数的代码,如下所示:

public class ExceptionHandler
{
    public static bool HandleException(Exception ex, IList<Param> parameters)
    {
        /*
         * Log the exception
         * 
         * Return true to rethrow the original exception,
         * else false
         */
    }
}

public class Param
{
    public string Name { get; set; }
    public object Value { get; set; }
}

public class MyClass
{
    public void RenderSomeText(int lineNumber, string text, RenderingContext context)
    {
        try
        {
            /*
             * Do some work
             */
            throw new ApplicationException("Something bad happened");
        }
        catch (Exception ex)
        {
            if (ExceptionHandler.HandleException(
                    ex, 
                    new List<Param>
                    {
                        new Param { Name = "lineNumber", Value=lineNumber },
                        new Param { Name = "text", Value=text },
                        new Param { Name = "context", Value=context}
                    }))
            {
                throw;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:或者,通过使参数HandleException为params数组:

public static bool HandleException(Exception ex, params Param[] parameters)
{
   ...
}

...
if (ExceptionHandler.HandleException(
                    ex, 
                    new Param { Name = "lineNumber", Value=lineNumber },
                    new Param { Name = "text", Value=text },
                    new Param { Name = "context", Value=context}
                    ))
{
    throw;
}
...
Run Code Online (Sandbox Code Playgroud)

生成额外的代码以显式地将参数传递给异常处理程序有点痛苦,但是使用加载项至少可以自动化它.

自定义属性可用于注释您不希望加载项传递给异常处理程序的任何参数:

public UserToken RegisterUser( string userId, [NoLog] string password )
{
}
Run Code Online (Sandbox Code Playgroud)

2ND编辑:

请注意,我完全忘记了AVICode:

http://www.avicode.com/

他们使用呼叫拦截技术来提供这种信息,因此它必须是可能的.


Wol*_*yrd 5

不幸的是,除了实际附加到应用程序的调试工具之外,您无法从调用堆栈中获取参数的实际值。但是,通过使用 System.Diagnostics 中的 StackTrace 和 StackFrame 对象,您可以遍历调用堆栈并读出所有调用的方法以及参数名称和类型。你会这样做:

System.Diagnostics.StackTrace callStack = new System.Diagnostics.StackTrace();
System.Diagnostics.StackFrame frame = null;
System.Reflection.MethodBase calledMethod = null;
System.Reflection.ParameterInfo [] passedParams = null;
for (int x = 0; x < callStack.FrameCount; x++)
{
    frame = callStack.GetFrame(x);
    calledMethod = frame.GetMethod();
    passedParams = calledMethod.GetParameters();
    foreach (System.Reflection.ParameterInfo param in passedParams)
        System.Console.WriteLine(param.ToString()); 
}
Run Code Online (Sandbox Code Playgroud)

如果您需要实际值,那么恐怕您将需要进行小型转储并分析它们。可以在以下位置找到有关获取转储信息的信息:

http://www.debuginfo.com/tools/clrdump.html

  • 这样做的问题是您从 Catch 内部获取堆栈,而不是发生异常时的堆栈。 (5认同)

Kil*_*fer 0

我不知道有这样的事情,但我自己也想要它。我通常在抛出异常时自己这样做,但如果不是你抛出异常,那么你可能会和我们其他人一起出去。