如何从其构造函数设置自定义异常类的 InnerException

Posted

技术标签:

【中文标题】如何从其构造函数设置自定义异常类的 InnerException【英文标题】:How to set the InnerException of custom Exception class from its constructor 【发布时间】:2010-11-30 19:24:48 【问题描述】:

当我在该对象的构造函数中时,如何设置Exception 对象的InnerException 属性?这归结为查找和设置没有设置器的属性的支持字段。

顺便说一句:我已经看到了这个evain.net - Getting the field backing a property using Reflection,但如果可能的话,我正在寻找非基于 IL 的解决方案。

Exception的构造函数是创建Exception类型的地方,所以我不能使用基类构造函数MyException() :base(...)等来调用它。

【问题讨论】:

重新跟进;然后(正如我提到的)在 ctor 的静态方法 ahead 中创建类型,而不是在构造函数主体内。 在我的情况下封装更有意义。 ...但我同意你的观点,我会考虑把它变成工厂以避免反射成本。 (fwiw,我没有说工厂;看看这个例子——你可以使用静态方法来做就在基础ctor之前,在对base的调用中; 你把你的工作放在这里,然后) 【参考方案1】:

在我的情况下,我使用了以下代码:

class Foo 

    void Bar(MyException myException = null)
    
        try
        
            SomeActions.Invoke();
        
        catch (Exception ex)
        
            if (myException != null)
            
                // Here I regenerate my exception with a new InnerException
                var regenMyException = (MyException)System.Activator.CreateInstance(myException.GetType(), myException.Message, ex);
                throw regenMyException;
            

            throw new FooBarException("Exception on Foo.Bar()", ex);
        
    

某人;)。

【讨论】:

【参考方案2】:

我知道我真的迟到了,但我发现这很管用。

public class MyException: Exception

    public void SetInnerException(Exception exception) 
    
        typeof(Exception)
            .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
            .SetValue(this, exception);
     

诀窍是获取实际的Exception 类型的_innerException 字段,然后将内部异常值设置为您的类实例(在本例中为MyException)。

这也适用于变量。

Exception mainException = new Exception();
typeof(Exception)
    .GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance)
    .SetValue(mainException , new Exception("Something bad happened!"));

【讨论】:

【参考方案3】:

使用 Redgate 的 Reflector 找到该字段。我怀疑 Exception 的实现会不会改变……但这是有风险的!

【讨论】:

你为什么会怀疑这一点?你有什么依据做这个评估?如果我是 Microsoft,我会更改实现,以对抗依赖其他人类的内部实现细节的傻瓜。 基于在过去的框架更新中更改的此类详细信息的数量? 真正的原因不是Exception 类的内部实现可能会改变。 (不能保证它不会,但没有理由相信它会。)相反,通过访问和修改私有字段,您违反了类不变量:只允许异常链接到现有异常并且永远不允许这种关联改变,保证异常链总是有限的并且永远不会递归循环到自身。【参考方案4】:

为什么不能直接调用以 InnerException 作为参数的构造函数?如果由于某种原因不可能,System.Exception 中的支持字段是:

private Exception _innerException;

我使用Redgate's Reflector 发现了它。使用反射我想你可以设置内部异常。

编辑:在大多数情况下,通过反射访问私有字段并不是一个好主意,但我对 NT 的情况了解不多,无法确定这是个好主意还是坏主意。

【讨论】:

我想不出一个合理的例子来说明反射是做到这一点的正确方法...... 这对于涉及激活异常的动态场景是有意义的,其中内部异常无法提前知道,因此无法传递给构造函数。 不,它没有。真的没有;它破坏了封装。在` : base(SomeMethod(...), ...)`链中使用静态方法。 @_NT:为了使内部异常有意义,它应该发生在当前异常之前。通常,您希望将异常向上冒泡...而不是向下冒泡。 顺便说一句...用反射改变私有和内部值可能会在未来引起重大变化。如果您这样做,后果自负。【参考方案5】:

您通过调用基本 ctor 来设置内部异常:

public MyException(string message, Exception innerException)
       : base(message, innerException) ...

如果需要运行一些代码来获取异常,请使用静态方法:

public MyException(SomeData data) : base(GetMessage(data), GetInner(data)) ...
static Exception GetInner(SomeData data) ... // <===== your type creation here!
static string GetMessage(SomeData data) ...

【讨论】:

【参考方案6】:

如果我理解你的问题,你想做这样的事情:

Exception ex = new Exception("test");
Exception innerEx = new Exception("inner");
ex.GetType().GetField("_innerException", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(ex, innerEx);

如果您在从 Exception 继承的对象的构造函数中,您将使用 this 而不是第一个 ex

但这可能不是处理您要处理的任何事情的最佳方式。

【讨论】:

异常有什么问题 innerEx = new Exception("inner");异常 ex = new Exception("test", innerEx); ? 他试图修改不是在上下文中创建的对象ex,我创建它只是为了演示。实际上,在他的情况下,他正在尝试修改 this 实例。 +1:这回答了我自己的相当愚蠢的问题,即如何强制异常的内部异常成为自身,从而导致有趣的事情,例如让 ToString() 方法触发堆栈溢出。 @Brian:这正是 .NET Framework 不公开设置内部异常的原因。如果异常可以链接到现有异常,并且这种关联永远不会改变,则异常链保证是有限的。如果您可以更改内部异常,则无法再做出此保证 - 您可以将异常链递归循环到自身。【参考方案7】:

Exception 类有一个接受内部异常作为参数的重载构造函数:

Exception exc = new Exception("message", new Exception("inner message"));

这是你要找的吗?

【讨论】:

虽然这并不能直接回答他的问题,但它回答了大多数搜索此内容的人正在寻找的内容。 @rollsch 是对的。【参考方案8】:

在使用Exception(string, Exception) 构造函数时不应该设置InnerException 吗?我认为这是设计使然,否则您无法更改此设置,但您始终可以在构建时遵循适当的构造函数:

class MyException : Exception 
    public MyException()
        : base("foo", new Exception("bar"))
    
        ...
    

    ...

我认为您永远不应该破坏代码中的异常链,因为这通常会导致您再也找不到错误。

【讨论】:

【参考方案9】:
Exception exceptionWithMoreInfo = new Exception("extra info", ex);

假设您已经捕获了一个异常,您希望在冒泡之前添加更多信息,这将是正常的做法。

【讨论】:

不过,这对异常的 ctor 没有帮助。

以上是关于如何从其构造函数设置自定义异常类的 InnerException的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中使用自定义构造函数创建异常 [重复]

java关于子类和父类构造方法的关系,犯迷糊!!

调用自定义 Button 类的构造函数时出现 ClassCastException

为啥需要自定义异常类[重复]

自定义异常

00086_自定义异常