如何在C#中更改Exception对象的Message
?
Message
的{{1}}属性只读:
Exception
在PHP中,同样的问题得到了回答,“你不能”,但给出了一个解决方法:
然而,您可以确定它的类名和代码,并使用相同的代码但使用不同的消息抛出相同类的新类。
如何确定异常的类名,并在C#中使用不同的消息抛出一个新的类名?
e.g:
public virtual string Message { get; }
不起作用,因为异常的catch (Exception e)
{
Exception e2 = Activator.CreateInstance(e.GetType());
throw e2;
}
属性是只读的和.NET。见原始问题。
更新
我尝试捕捉我期望的每种类型的异常:
Message
现在我的代码强制依赖于每个解决方案中都不会出现的程序集。
此外,现在异常似乎来自我的代码,而不是抛出它的行;我丢失了例外的位置信息
答案 0 :(得分:29)
您创建一个新的Exception
(或更好的特定子类型),其中包含新消息(并将原始异常作为InnerException
传递)。
例如
throw new MyExceptionType("Some interesting message", originalException);
NB。如果你真的想使用Activator.CreateInstance
,你可以使用可以传递参数的重载,但是不能依赖不同的Exception派生类型来为(message, innerException)
创建一个构造函数。
答案 1 :(得分:17)
我在a blog post中找到了a news site中的解决方案:
catch (Exception e)
{
Exception e2 = (Exception)Activator.CreateInstance(e.GetType(), message, e);
throw e2;
}
它并不完美(你丢失了堆栈痕迹);但这就是.NET的本质。
答案 2 :(得分:7)
我只是想在这里与Ian相关的答案。如果您在blog post中使用该技术,则不会丢失堆栈。是的,您将丢失最终异常的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);
}
}
}
如果您获取异常的完整字符串,您将获得:
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
所以你无论如何都得到了整个筹码,加上额外的信息
答案 3 :(得分:4)
您可以使用新消息将先前的异常包装在新的异常中,并使用堆栈跟踪的内部异常/等。
try
{
throw new Exception("This error message sucks");
}
catch (Exception e)
{
throw new Exception("There error message is prettier", e);
}
答案 4 :(得分:1)
处理此问题的最佳方法是编写适合此特定情况的自己的异常类。然后捕获异常,并抛出自己的异常。您可能希望在此处看到:http://msdn.microsoft.com/en-us/library/ms229064.aspx了解更多信息。
如果您认为不需要客户例外,则应该能够在抛出异常时将自定义字符串传递给Exception构造函数:http://msdn.microsoft.com/en-us/library/48ca3hhw.aspx
答案 5 :(得分:1)
我知道这是一个非常古老的问题,但我不认为任何现有的答案都是理想的(它们隐藏了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;
}
}
所以你现在可以抛出:
throw CustomException.FromAlert(theAlert);
并将信息修改为您心中的内容。
答案 6 :(得分:1)
您可以像这样通过反射来更改异常消息...
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);
因此您可以创建扩展方法...
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);
}
}
}
然后使用它...
...
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
}
}
}
如果要使用“ throw ex;”,必须记住;堆栈跟踪将丢失。
要避免这种情况,请使用“ throw;”。毫无例外。
答案 7 :(得分:0)
在我的小老观点中,最好的方法是从Exception(或其他一些框架提供的异常类)继承,然后将您的消息字符串放入对基本构造函数的调用中,该构造函数将Message作为参数,像这样:
public class InvalidGraphicTypeException : Exception
{
public InvalidGraphicTypeException(Graphic badType) :
base("Invalid Graphic Type: " + badType.GetType().Name)
{
}
}