C# 在 .net Exception 中如何获取带有参数值的堆栈跟踪
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/157911/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In a .net Exception how to get a stacktrace with argument values
提问by Caerbanog
I am trying to add an unhandled exception handler in .net (c#) that should be as helpfull for the 'user' as possible. The end users are mostly programers so they just need a hint of what object are they manipulating wrong.
我正在尝试在 .net (c#) 中添加一个未处理的异常处理程序,它应该对“用户”尽可能有帮助。最终用户大多是程序员,所以他们只需要提示他们操作错误的对象。
I'm developing a windows similar to the windows XP error report when an application crashes but that gives as much imediate information as possible imediatly about the exception thrown.
我正在开发一个类似于 Windows XP 错误报告的窗口,当应用程序崩溃时,它会立即提供尽可能多的关于抛出的异常的即时信息。
While the stack trace enables me (since I have the source code) to pinpoint the source of the problem, the users dont have it and so they are lost without further information. Needless to say I have to spend lots of time supporting the tool.
虽然堆栈跟踪使我(因为我有源代码)能够查明问题的根源,但用户没有它,因此他们在没有进一步信息的情况下丢失了。不用说,我必须花费大量时间来支持该工具。
There are a few system exceptions like KeyNotFoundException thrown by the Dictionary collection that really bug me since they dont include in the message the key that wasnt found. I can fill my code with tons of try catch blocks but its rather agressive and is lots more code to maintain, not to mention a ton more of strings that have to end up being localized.
有一些系统异常,比如 Dictionary 集合抛出的 KeyNotFoundException 真的让我感到困扰,因为它们没有在消息中包含未找到的键。我可以用大量的 try catch 块填充我的代码,但它相当具有攻击性,并且需要维护更多的代码,更不用说大量必须最终被本地化的字符串。
Finally the question: Is there any way to obtain (at runtime) the values of the arguments of each function in the call stack trace? That alone could resolve 90% of the support calls.
最后一个问题:有没有办法(在运行时)获取调用堆栈跟踪中每个函数的参数值?仅此一项就可以解决 90% 的支持电话。
回答by Kilhoffer
I'm not aware of anything like that, but have wanted it myself. I usually do it myself when throwing exceptions, but if it's not yours to throw, then you may be out with the rest of us.
我不知道这样的事情,但我自己想要。我通常在抛出异常时自己做,但如果不是你抛出的,那么你可能会和我们其他人一起出去。
回答by Peter Meyer
I don't believe there is a built-in mechanism. Retrieving each frame of the stack trace, while allowing you to determine the method in the trace, only gives you the reflected type information on that method. No parameter information. I think this is why some exceptions, notably, ArgumentException, et. al. provide a mechanism to specify the value of the argument involved in the exception since there's no easy way to get it.
我不相信有一个内置的机制。检索堆栈跟踪的每一帧,同时允许您确定跟踪中的方法,只为您提供该方法的反射类型信息。无参数信息。我认为这就是为什么会有一些例外,特别是 ArgumentException 等。阿尔。提供一种机制来指定异常中涉及的参数的值,因为没有简单的方法来获取它。
回答by user7375
I don't think System.Diagnostics.StackFrame supplies argument information (other than the method signature).
我不认为 System.Diagnostics.StackFrame 提供参数信息(方法签名除外)。
You could instrument the troublesome calls with trace logging via AOP, or even use its exception interception features to conditionally log without having to litter your code. Have a look around http://www.postsharp.org/.
您可以通过 AOP 使用跟踪日志记录来检测麻烦的调用,甚至可以使用其异常拦截功能来有条件地记录日志,而不必乱扔代码。看看http://www.postsharp.org/。
回答by Andrew
I don't know a way to obtain the values of the arguments of each function in the call stack trace, but one solution would be to catch the specific exception (KeyNotFoundException
in your example) and re-throw it in a new Exception. That allows you associate any additional information you wish
我不知道在调用堆栈跟踪中获取每个函数的参数值的方法,但一种解决方案是捕获特定异常(KeyNotFoundException
在您的示例中)并在新异常中重新抛出它。这允许您关联任何您希望的附加信息
For example:
例如:
Dim sKey as String = "some-key"
Dim sValue as String = String.Empty
Try
sValue = Dictionary(sKey)
Catch KeyEx As KeyNotFoundException
Throw New KeyNotFoundException("Class.Function() - Couldn't find [" & sKey & "]", KeyEx)
End Try
I appreciate your statement about localising the error strings, but if your audience are 'mostly programmers' then convention already dictates a comprehension of English to some degree (rightly or wrongly - but that's another debate!)
我很欣赏你关于本地化错误字符串的声明,但如果你的听众“主要是程序员”,那么惯例已经在一定程度上决定了对英语的理解(正确或错误 - 但这是另一场辩论!)
回答by Vivek
Since the end users are developers, you can provide them with a version that enables logging of all the key values/arguments that are passed. And provide a facility so that they can turn on/off logging.
由于最终用户是开发人员,您可以为他们提供一个版本,以便记录所有传递的键值/参数。并提供一个工具,以便他们可以打开/关闭日志记录。
回答by slf
回答by Wolfwyrd
Unfortunately you can't get the actual values of parameters from the callstack except with debugging tools actually attached to the application. However by using the StackTrace and StackFrame objects in System.Diagnostics you can walk the call stack and read out all of the methods invoked and the parameter names and types. You would do this like:
不幸的是,除非使用实际附加到应用程序的调试工具,否则您无法从调用堆栈中获取参数的实际值。但是,通过使用 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());
}
If you need actual values then you're going to need to take minidumps and analyse them i'm afraid. Information on getting dump information can be found at:
如果您需要实际值,那么恐怕您将需要进行小型转储并分析它们。可以在以下位置找到有关获取转储信息的信息:
回答by Steven A. Lowe
it is theoretically possible to do what you want by taking advantage of the Portable Executable (PE) file format to get the variable types and offsets, but I ran into a [documentation] wall trying to do this a couple of years ago. Good luck!
理论上可以通过利用可移植可执行文件 (PE) 文件格式来获取变量类型和偏移量来做您想做的事情,但是几年前我遇到了 [文档] 墙试图这样做。祝你好运!
回答by leppie
If you could do what you are looking for, you would be defeating an integral part of .NET security.
如果你能做你想要的,你就会打败 .NET 安全的一个组成部分。
The best option in the case, it to attach to a debugger or profiler (either of them can access those values). The former can be attached, the latter need to be active before the program starts.
在这种情况下,最好的选择是附加到调试器或分析器(它们中的任何一个都可以访问这些值)。前者可以附加,后者需要在程序启动前激活。
回答by Steve Morgan
Likewise, I've not found anything to derive the parameters automatically at runtime. Instead, I've used a Visual Studio add-in to generate code that explicitly packages up the parameters, like this:
同样,我没有找到任何可以在运行时自动派生参数的东西。相反,我使用了 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;
}
}
}
}
EDIT: or alternatively, by making the parameter to HandleException a params array:
编辑:或者,通过将 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;
}
...
It's a bit of a pain generating the extra code to explicitly pass the parameters to the exception handler, but with the use of an add-in you can at least automate it.
生成额外的代码来显式地将参数传递给异常处理程序有点麻烦,但是通过使用加载项,您至少可以自动化它。
A custom attribute can be used to annotate any parameters that you don't want the add-in to pass to the exception handler:
自定义属性可用于注释您不希望加载项传递给异常处理程序的任何参数:
public UserToken RegisterUser( string userId, [NoLog] string password )
{
}
2ND EDIT:
第二次编辑:
Mind you, I'd completely forgotten about AVICode:
请注意,我完全忘记了 AVICode:
They use call interception techniques to provide exactly this kind of information, so it must be possible.
他们使用呼叫拦截技术来准确提供此类信息,因此它必须是可能的。