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

lnvxswe2  于 2023-01-10  发布在  .NET
关注(0)|答案(9)|浏览(187)

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

奖励聊天

ExceptionMessage属性为 * 只读 *:

public virtual string Message { get; }

附加读数

同样的问题,在PHP中,回答是 "你不能",但给出了一个变通方案:
但是,您可以确定它的类名和代码,然后抛出一个新的类,它属于同一个类,具有相同的代码,但具有不同的消息。
在C#中,我如何确定一个异常的类名,并抛出一个相同类的新类名,但使用不同的消息?
例如:

catch (Exception e)
{
   Exception e2 = Activator.CreateInstance(e.GetType());
   throw e2;
}

不起作用,因为异常的Message属性是只读的并且是. NET。

    • 更新**

我尝试捕获我期望的每种类型的异常:

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);
}

只是现在我的代码强制依赖于程序集,而这并不是每个解决方案中都存在的。
而且,现在异常似乎来自我的代码,而不是引发它的那一行;我丢失了异常的位置信息

flmtquvp

flmtquvp1#

创建一个新的Exception(或者更好的特定子类型),它包含新消息(并将原始异常作为InnerException传递)。
例如:

throw new MyExceptionType("Some interesting message", originalException);

注意:如果你真的想使用Activator.CreateInstance,你可以使用一个可以传递参数的重载,但是不同的Exception派生类型不能依赖于(message, innerException)的构造函数重载。

41zrol4v

41zrol4v2#

我在a blog post中找到了从a news site链接的解决方案:

catch (Exception e)
{
   Exception e2 = (Exception)Activator.CreateInstance(e.GetType(), message, e);
   throw e2;
}

它并不完美(您会丢失堆栈跟踪);但这就是. NET的本质

0yycz8jy

0yycz8jy3#

我只是想在这里为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

所以你得到了整个堆栈,加上额外的信息

lnxxn5zx

lnxxn5zx4#

您可以通过反射更改异常消息,如下所示...

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
        }
    }
}

你必须记住如果你使用“throwex;“堆栈跟踪将丢失
要避免这种情况,必须使用“throw;“无一例外**。

fnvucqvd

fnvucqvd5#

您可以将先前的异常 Package 在一个包含新消息的新异常中,并将内部异常用于堆栈跟踪等。

try
{
    throw new Exception("This error message sucks");
}
catch (Exception e)
{
    throw new Exception("There error message is prettier", e);
}
llew8vvj

llew8vvj6#

在我看来,最好的方法是从Exception(或其他框架提供的异常类)继承,然后将消息字符串放在对基构造函数的调用中,该构造函数将Message作为参数,如下所示:

public class InvalidGraphicTypeException : Exception
{

   public InvalidGraphicTypeException(Graphic badType) : 
      base("Invalid Graphic Type: " + badType.GetType().Name)
   {
   }
}
quhf5bfb

quhf5bfb7#

我知道这是一个很老的问题,但我不认为任何现有的答案是理想的(他们隐藏异常细节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;
    }
}

因此,您现在可以抛出:
第一个月
把信息修改到你满意的程度。

rhfm7lfc

rhfm7lfc8#

处理这个问题的最好方法是编写适合这种特殊情况的自己的异常类。然后捕获异常,并抛出自己的异常。您可能希望看到以下内容:Exception Constructors -> Exception(String) | MS Docs了解更多信息。
如果您觉得自定义异常不是必需的,则应该能够在引发异常时将自定义字符串传递给Exception构造函数:设计Custom Exceptions | MS Docs

niwlg2el

niwlg2el9#

它是虚拟的(在Net4.6和Net6中),所以你可以在你的自定义异常类中覆盖它。
下面是一个如何在Net4.6中提取WebException响应消息并将其放入Message Property的示例。

public class ConnectionProblem : Exception
{
    private string CustomMessage { get; }
    public ConnectionProblem(Exception ex) : base(ex.Message, ex)
    {
        if (ex is System.Net.WebException)
        {//extract error
            var wex = (WebException)ex;
            var resStream = wex.Response.GetResponseStream();
            var resBytes = resStream.ReadToEnd();
            var resMsg = System.Text.Encoding.UTF8.GetString(resBytes);
            CustomMessage = $"{nameof(ConnectionProblem)} encounter with type {nameof(WebException)}, response got: '{resMsg}'";
        }
    }
    public override string Message => CustomMessage;
}

相关问题