.net - 如何更改Exception对象的异常消息?

时间:2012-02-17 19:29:35

标签: .net exception

如何在C#中更改Exception对象的Message

Bonus Chatter

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

现在我的代码强制依赖于每个解决方案中都不会出现的程序集。

此外,现在异常似乎来自我的代码,而不是抛出它的行;我丢失了例外的位置信息

8 个答案:

答案 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)
   {
   }
}