简体   繁体   English

捕获/修改(消息)/ Rethrow相同类型的异常

[英]Catch/Modify (Message)/Rethrow Exception of same type

I want a central place to extract information from an exception, set all the information I need to its message parameter and then rethrow that information as an Exception of the same type. 我想要一个中心位置从异常中提取信息,将我需要的所有信息设置为其消息参数,然后将该信息重新抛出为相同类型的异常。

The better solution probably would be to do this at the place where the exception is finally being handled (and its message logged), but.. I have control over the place throwing the exception, and not over the place that receives the exception and only logs its Message content. 更好的解决方案可能是在最终处理异常的地方执行此操作(并记录其消息),但是..我可以控制抛出异常的地方,而不是接收异常的地方记录其消息内容。

Apart from that design decision and given that message is a readonly property, I would have (?) to create a new Exception object in some way, is there a way to make the new exception object the same type as the original one? 除了那个设计决定,并且假设message是一个readonly属性,我会(?)以某种方式创建一个新的Exception对象,有没有办法让新的异常对象与原始异常对象相同?

Here is my code, which does not compile - it stumbles over the throw line (where I try to dynamically cast the object). 这是我的代码,它不编译 - 它偶然发现了抛出线(我尝试动态转换对象)。

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

Does this 做这个

throw (Exception)newEx;

preserve the type? 保留类型? (It compiles.) (它汇编。)

Does the Convert.ChangeType make sure I get an Exception of the correct type? Convert.ChangeType是否确保我得到了正确类型的异常?

What you are trying to do here is not as easy as it seems and there are lots of pitfalls to consider. 你在这里想要做的并不像看起来那么容易,而且还有很多陷阱需要考虑。

Remember, that Convert.ChangeType() will convert one type to another (assuming such a path exists, like converting a string to an int for example). 请记住,Convert.ChangeType()会将一种类型转换为另一种类型(假设存在这样的路径,例如将字符串转换为int)。 Most exceptions wont do this (Why would they?) 大多数例外不会这样做(为什么会这样?)

IN order to pull this off, you would have to examine the exception type at runtime with the GetType() method and locate a constructor that has requirements you can satisfy and invoke it. 为了解决此问题,您必须使用GetType()方法在运行时检查异常类型,并找到具有您可以满足的要求并调用它的构造函数。 Be careful here, since you don't have control over how all exceptions are defined there is no guarantee you will have access to "standard" constructors. 这里要小心,因为您无法控制如何定义所有异常,因此无法保证您可以访问“标准”构造函数。

That being said, if you feel like being a rule breaker you could do something like this... 话虽这么说,如果你觉得自己是一个规则破坏者,你可以做这样的事......

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

You could do this to dynamically call the constructor of the exception type: 您可以这样做来动态调用异常类型的构造函数:

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

Your original code would fail at runtime, because for Convert.ChangeType towork, the exception type would have to implement IConvertible and support conversion to the other exception type, which i doubt. 您的原始代码在运行时会失败,因为对于Convert.ChangeType towork,异常类型必须实现IConvertible并支持转换为另一种异常类型,我怀疑。

May be it's a bit late, but would this work for you? 可能有点晚了,但这对你有用吗?

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

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 . 堆栈跟踪将丢失

To avoid this you must use "throw;" 要避免这种情况, 你必须使用“throw;” without the exception . 没有例外

Supplemental comment. 补充评论。

These all work in supplementing the exception message, but I found that using "throw" did NOT preserve the StackTrace - the last trace pointed to the actual "throw" statement (dropping the root cause location). 这些都可以补充异常消息,但是我发现使用“throw”并没有保留StackTrace - 最后一个跟踪指向实际的“throw”语句(删除根本原因位置)。

From discussions elsewhere, it's clear there are some circumstances that throw doesn't preserve due to CLR stack limitations 从其他地方的讨论中可以清楚地看出,由于CLR堆栈限制,有些情况下抛出不会保留

Throw and preserve stack trace not as expected as described by Code Analysis 不像代码分析所描述的那样抛出和保留堆栈跟踪

Solution: dump the StackTrace in each exception (eg and add to the error message) and/or dump to logging 解决方案:在每个异常中转储StackTrace(例如,添加到错误消息)和/或转储到日志记录

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM