如何在不丢失 C# 中的任何信息的情况下向异常添加消息?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14409988/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:43:41  来源:igfitidea点击:

How can I add a message to an exception without losing any information in C#?

c#exceptionexception-handling

提问by Codeman

I have the following code:

我有以下代码:

catch(Exception ex)
{
    throw new FatalException("An error occurred while trying to load the XSLT file.", ex);
}

This unfortunately just swallows up the Exception. I can fix this by doing the following:

不幸的是,这只是吞噬了异常。我可以通过执行以下操作来解决此问题:

catch(Exception ex)
{
    throw;
}

But I would still like to include the custom message for help with event logging.

但我仍然希望包含自定义消息以获取事件记录方面的帮助。

How do I add this message to the exception without losing any information? (stack trace/debug symbols, etc.)

如何在不丢失任何信息的情况下将此消息添加到异常中?(堆栈跟踪/调试符号等)

采纳答案by competent_tech

If you just need to add information to the original exception, such as a user-readable message or specific details that will be useful to you in tracking down the error but that won't be useful to the end user, you can make use of the Exception's Dataproperty, which is a key/value pair dictionary.

如果您只需要向原始异常添加信息,例如用户可读的消息或特定详细信息,这些信息对您跟踪错误有用但对最终用户没有用,您可以使用Exception 的Data属性,它是一个键/值对字典。

We use this extensively in order to record information such as the report being executed or file that is being processed so that operations can determine what exactly was happening at the time of the error. The user doesn't need this detail since they are working directly with the cause of the failure.

我们广泛使用它来记录诸如正在执行的报告或正在处理的文件等信息,以便操作可以确定发生错误时究竟发生了什么。用户不需要这个细节,因为他们直接处理失败的原因。

You could also use this to pass a plain text message that makes sense to the user. The only issue is that you will have to perform some additional work in your logging framework or end-user interface in order to extract the data and make it useful to the consumer.

您还可以使用它来传递对用户有意义的纯文本消息。唯一的问题是您必须在日志框架或最终用户界面中执行一些额外的工作,以便提取数据并使其对消费者有用。

For example, you could do:

例如,你可以这样做:

catch (Exception ex)
{
    ex.Data.Add("UserMessage", "An error occurred while trying to load the XSLT file.");
    throw;
}

Then in the client-side code, you could test to see if UserMessage exists and, if so, present it to the user instead of the Exception:

然后在客户端代码中,您可以测试以查看 UserMessage 是否存在,如果存在,则将其呈现给用户而不是 Exception:

catch (Exception ex)
{
    if (ex.Data.Contains("UserMessage"))
    {
        MessageBox.Show(ex.Data["UserMessage"].ToString());
    }
    else
    {
        MessageBox.Show(ex.Message);
    }
}

回答by krillgar

That original Exception is still there.

那个原始的 Exception 仍然存在。

When you do your Exception logging, the Exception that you receive will be the FatalException that you made with your message. The original Exception is in ex.InnerException. You can continue to cycle through InnerException until it's null to get all of the Stack Trace information, etc.

当您进行 Exception 日志记录时,您收到的 Exception 将是您使用消息创建的 FatalException。原始异常在ex.InnerException. 您可以继续循环遍历 InnerException 直到它为 null 以获取所有 Stack Trace 信息等。

回答by p.s.w.g

In short, don't.

简而言之,不要。

I'm sure you could find some way of getting around this with some reflection, but I would stronglycaution you against this. It goes against the original design of exceptions in .NET. Exceptions are not just there to help with logging, they provide information about the original cause of an application failure.

我相信你可以通过一些反思找到解决这个问题的方法,但我会强烈警告你不要这样做。它违背了 .NET 中异常的原始设计。异常不仅可以帮助记录日志,还可以提供有关应用程序失败的原始原因的信息。

Using the first option is generally preferred as it maintains the stack trace of the original exception but allows you to provide additional information by wrapping it in a separate exception. In my own code, whenever I log exceptions, my logging function will recurse through the InnerException property to find every bit of useful information possible about the error.

通常首选使用第一个选项,因为它维护原始异常的堆栈跟踪,但允许您通过将其包装在单独的异常中来提供其他信息。在我自己的代码中,每当我记录异常时,我的记录函数将通过 InnerException 属性递归查找有关错误的所有有用信息。

回答by George

Just in case someone needs a good answer. The key is to use AppDomain.CurrentDomain.FirstChanceException

以防万一有人需要一个好的答案。关键是使用 AppDomain.CurrentDomain.FirstChanceException

The you can create a custom object with IDisposable to put all info in it. And if exception happens then FirstChanceException handler gets that info and populate Exception.Data.

您可以使用 IDisposable 创建自定义对象以将所有信息放入其中。如果发生异常,则 FirstChanceException 处理程序获取该信息并填充 Exception.Data。

Use Local Thread Storage to make it thread safe. Then down the line the code that catches it will get the data and log it.

使用本地线程存储使其线程安全。然后,捕获它的代码将获取数据并记录下来。

Example:

例子:

using(MyCustomMessage.EnterToLocalStorage("Info for logging"") ) 
{ 
...code 
...exception thrown
.... FirstChanceException examines local thread storage and get's "info for logging" and puts into Exception.Data. 
} 
//Dispose is called and all messages that were put into LocalStorage are removed. 
//So if exception was not thrown before then it like nothing happened.

Google AsyncDiagnosticStack for a good example. https://github.com/StephenCleary/AsyncDiagnostics/blob/master/src/Nito.AsyncEx.AsyncDiagnostics/AsyncDiagnosticStack.cs

谷歌 AsyncDiagnosticStack 就是一个很好的例子。https://github.com/StephenCleary/AsyncDiagnostics/blob/master/src/Nito.AsyncEx.AsyncDiagnostics/AsyncDiagnosticStack.cs