捕获/修改(消息)相同类型的/重新抛出异常(Catch/Modify (Message)/Rethr

2019-09-20 05:52发布

我想一个中心位置,从异常提取信息,设置我需要它的消息参数的所有信息,然后再次抛出该信息作为同一类型的异常。

更好的解决方案可能会在在异常终于被处理(和它的消息记录)的地方要做到这一点,但是..我有过抛出异常的地方控制,而不是在接收例外,唯一的地方记录其信息的内容。

除此之外,设计决定,并给予该消息是一个只读属性,我会(?)以某种方式来创建一个新的异常对象,有没有一种方法,使新的异常对象相同的类型和原来的?

这里是我的代码,不编译 - 它绊倒了罚球线(在这里我将尝试动态投的对象)。

public static void RethrowExceptionWithFullDetailInMessage(string msg, Exception ex)
{
    Exception curEx = ex;
    int cnt = 0;
    while (curEx != null)
    {
        msg += "\r\n";
        msg += cnt++ + " ex.message: " + curEx.Message + "\r\n";
        msg += "Stack: " + curEx.StackTrace;
        curEx = curEx.InnerException;
    }
    object newEx = Convert.ChangeType(new Exception(msg), ex.GetType());
    throw (ex.GetType())newEx;
}

做这个

throw (Exception)newEx;

保存类型? (它编译。)

是否Convert.ChangeType确保我得到正确类型的异常?

Answer 1:

因为它似乎有很多陷阱考虑你正在尝试做的,是不容易。

记住,Convert.ChangeType()将一种类型转换到另一种(假定这样的路径存在,像一个字符串转换为例如一个int)。 大多数异常不会做到这一点(为什么他们会吗?)

为了拉这一关,你就必须检查在与的GetType()方法运行时异常类型,找到有你能满足并调用它要求一个构造函数。 这里要小心,因为你没有在所有异常是如何定义也不能保证你将有机会获得“标准”构造控制。

话虽这么说,如果你觉得自己是一个规则破坏者,你可以做这样的事情?

void Main()
{
    try
    {   
        throw new Exception("Bar");
    }
    catch(Exception ex)
    {
        //I spit on the rules and change the message anyway
        ex.GetType().GetField("_message", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(ex, "Foo");
        throw ex;
    }
}


Answer 2:

你可以这样做动态调用异常类型的构造函数:

object newEx = Activator.CreateInstance(ex.GetType(), new object[] { msg });

您原来的代码将在运行时失败,因为Convert.ChangeType towork,异常的类型必须实现IConvertible和支持转换到其他异常类型,我怀疑。



Answer 3:

可能这是一个有点晚了,但这样做对你的工作?

catch (Exception ex)
{
    throw new Exception("New message", ex);
}


Answer 4:

你可以通过这样的反射发生变化异常消息...

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

你必须记住, 如果你用“扔恩;” 堆栈跟踪将会丢失

为了避免这种情况,你必须使用“抛”; 没有例外



文章来源: Catch/Modify (Message)/Rethrow Exception of same type