.net - 如何更改异常对象的异常消息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9334182/
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
.net - How to change exception message of Exception object?
提问by Ian Boyd
How can i change the Messageof an Exception object in C#?
如何Message在 C# 中更改Exception 对象的类型?
Bonus Chatter
奖金喋喋不休
The Messageproperty of Exceptionis read-only:
的Message属性Exception是只读的:
public virtual string Message { get; }
Additional Reading
补充阅读
The same question, in PHP, was answered, "You can't", but gave a workaround:
同样的问题,在 PHP 中,得到了回答,"You can't",但提供了一个解决方法:
You can however determine it's class name and code, and throw a new one, of the same class, with same code, but with different message.
然而,您可以确定它的类名和代码,并抛出一个新的,相同的类,具有相同的代码,但具有不同的消息。
How can i determine an exception's class name, and throw a new one of the same class, but with a different message, in C#?
在 C# 中,如何确定异常的类名,并抛出同一个类的新类,但具有不同的消息?
e.g.:
例如:
catch (Exception e)
{
Exception e2 = Activator.CreateInstance(e.GetType());
throw e2;
}
doesn't work because the Messageproperty of an exception is read-only and .NET. See original question.
不起作用,因为Message异常的属性是只读的和 .NET。请参阅原始问题。
Update
更新
i tried catching each type of exception i expect:
我尝试捕获我期望的每种类型的异常:
try
{
reader.Read();
}
catch (OleDbException e)
{
throw new OleDbException(e, sql);
}
catch (SqlException e)
{
throw new SqlException (e, sql);
}
catch (IBM.DbException e)
{
throw new IBM.DbException(e, sql);
}
catch (OdbcException e)
{
throw new OdbcException (e, sql);
}
catch (OracleException e)
{
throw new OracleException (e, sql);
}
Except that now my code forces a dependency on assemblies that won't be present in every solution.
除了现在我的代码强制依赖于不会出现在每个解决方案中的程序集。
Also, now the exception seems to come from my code, rather than the line that threw it; i lose the exception's location information
此外,现在异常似乎来自我的代码,而不是抛出它的行;我丢失了异常的位置信息
采纳答案by Ian Boyd
i found the solution in a blog postlinked from a news site:
catch (Exception e)
{
Exception e2 = (Exception)Activator.CreateInstance(e.GetType(), message, e);
throw e2;
}
It's not perfect (you lose your stack trace); but that's the nature of .NET.
它并不完美(您丢失了堆栈跟踪);但这就是 .NET 的本质。
回答by Richard
You create a new Exception(or – better – specific subtype) that has the new message (and pass the original exception as InnerException).
您创建了一个新的Exception(或更好的特定子类型),它具有新消息(并将原始异常作为 传递InnerException)。
Eg.
例如。
throw new MyExceptionType("Some interesting message", originalException);
NB. If you really want to use Activator.CreateInstanceyou can use an overload that can be passed parameters, but different Exception derived types cannot be relied on to have an constructor overload for (message, innerException).
注意。如果你真的想使用Activator.CreateInstance你可以使用一个可以传递参数的重载,但是不能依赖不同的 Exception 派生类型来为(message, innerException).
回答by devshorts
I just wanted to chime in here for Ian related to his answer. If you use the technique in the blog postyou won't lose the stack. Yes, you will lose the stack in the member of StackTraceof the final exception, but you won't lose the stack overall because of the inner exceptions. Look here:
我只是想在这里为 Ian 与他的回答有关。如果您使用博客文章中的技术,您将不会丢失堆栈。是的,您将丢失StackTrace最终异常的成员中的堆栈,但您不会因为内部异常而丢失整个堆栈。看这里:
class Program
{
static void Main(string[] args)
{
try
{
Test1();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public static void Test1()
{
try
{
Test2();
}
catch (Exception ex)
{
throw ExceptionUtil.Rethrow(ex, "caught in test1");
}
}
public static void Test2()
{
throw new Exception("test2");
}
public static class ExceptionUtil
{
public static Exception Rethrow(Exception ex, string message)
{
if (ex == null)
{
ex = new Exception("Error rethrowing exception because original exception is <null>.");
}
Exception rethrow;
try
{
rethrow = (Exception)Activator.CreateInstance(ex.GetType(), message, ex);
}
catch (Exception)
{
rethrow = new Exception(message, ex);
}
return rethrow;
}
public static Exception Rethrow(Exception ex, string message, params object[] args)
{
string formatted;
try
{
formatted = String.Format(message, args);
}
catch (Exception ex2)
{
formatted = message + "\r\n\r\nAn error occurred filling in exception message details:\r\n\r\n" + ex2;
}
return Rethrow(ex, formatted);
}
}
}
If you take the exception's full string you'll get:
如果您采用异常的完整字符串,您将得到:
System.Exception: caught in test1 ---> System.Exception: test2
at ScratchPad2.Program.Test2() in C:\Projects\Experiments\ScratchPad2\Program.cs:line 36
at ScratchPad2.Program.Test1() in C:\Projects\Experiments\ScratchPad2\Program.cs:line 26
--- End of inner exception stack trace ---
at ScratchPad2.Program.Test1() in C:\Projects\Experiments\ScratchPad2\Program.cs:line 30
at ScratchPad2.Program.Main(String[] args) in C:\Projects\Experiments\ScratchPad2\Program.cs:line 14
So you got the whole stack anyways, plus extra information
所以无论如何你都得到了整个堆栈,加上额外的信息
回答by Reddog
You can wrap the previous exception in a new one with your new message and make use of the inner exception for the stack trace/etc.
您可以使用新消息将先前的异常包装在一个新的异常中,并使用堆栈跟踪/等的内部异常。
try
{
throw new Exception("This error message sucks");
}
catch (Exception e)
{
throw new Exception("There error message is prettier", e);
}
回答by FrustratedWithFormsDesigner
The best way to handle this would be to write your own exception class that fits this particular situation. Then catch the exception, and throw your own Exception. You might want to see here: http://msdn.microsoft.com/en-us/library/ms229064.aspxfor more info.
处理这个问题的最好方法是编写适合这种特殊情况的自己的异常类。然后捕获异常,并抛出您自己的异常。您可能希望在此处查看:http: //msdn.microsoft.com/en-us/library/ms229064.aspx了解更多信息。
If you feel a customer exception is not necessary, you should be able to pass a custom string to the Exception constructor when throwing an exception: http://msdn.microsoft.com/en-us/library/48ca3hhw.aspx
如果您觉得不需要客户异常,您应该能够在抛出异常时将自定义字符串传递给 Exception 构造函数:http: //msdn.microsoft.com/en-us/library/48ca3hhw.aspx
回答by philologon
In my little old opinion, the best way to do it is inherit from Exception (or some other framework-supplied exception class as appropriate), then put your message string in a call to the base constructor which takes Message as a parameter, like so:
在我的旧观点中,最好的方法是从 Exception(或其他一些框架提供的适当异常类)继承,然后将您的消息字符串放入对将 Message 作为参数的基本构造函数的调用中,就像这样:
public class InvalidGraphicTypeException : Exception
{
public InvalidGraphicTypeException(Graphic badType) :
base("Invalid Graphic Type: " + badType.GetType().Name)
{
}
}
回答by Arbiter
I know this is a very old question but I don't think any of the existing answers are ideal (they hide exception details in innerExceptions or mask line numbers). The approach I use is to instantiate the exception using a static factory method instead of the constructor:
我知道这是一个非常古老的问题,但我认为现有的任何答案都不理想(它们在 innerExceptions 或掩码行号中隐藏了异常详细信息)。我使用的方法是使用静态工厂方法而不是构造函数来实例化异常:
public class CustomException {
public string SampleProperty { get; set; }
public static CustomException FromAlert(Alert alert)
{
var ex = new CustomException(string.Format("{0}-{1}", alert.propertyA, alert.propertyB));
ex.SampleProperty = "somethign else";
return ex;
}
}
So you can now throw:
所以你现在可以抛出:
throw CustomException.FromAlert(theAlert);
throw CustomException.FromAlert(theAlert);
And modify the message to your hearts content.
并将消息修改为您心中的内容。
回答by Piero álvarez
You can change the exception message via reflection like this...
您可以像这样通过反射更改异常消息...
Exception exception = new Exception("Some message.");
var type = typeof(Exception);
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var fieldInfo = type.GetField("_message", flags);
fieldInfo.SetValue(exception, message);
So you can create an extension method...
所以你可以创建一个扩展方法......
namespace ExceptionExample
{
public static class ExceptionExtensions
{
public static void SetMessage(this Exception exception, string message)
{
if (exception == null)
throw new ArgumentNullException(nameof(exception));
var type = typeof(Exception);
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var fieldInfo = type.GetField("_message", flags);
fieldInfo.SetValue(exception, message);
}
}
}
And then use it...
然后用它...
...
using static ExceptionExample.ExceptionExtensions;
public class SomeClass
{
public void SomeMethod()
{
var reader = AnotherClass.GetReader();
try
{
reader.Read();
}
catch (Exception ex)
{
var connection = reader?.Connection;
ex.SetMessage($"The exception message was replaced.\n\nOriginal message: {ex.Message}\n\nDatabase: {connection?.Database}");
throw; // you will not lose the stack trace
}
}
}
You have to keep in mind that if you use "throw ex;" the stack trace will be lost.
你必须记住,如果你使用“throw ex;” 堆栈跟踪将丢失。
To avoid this you must use "throw;" without the exception.
为避免这种情况,您必须使用“throw;” 无一例外。

