如何从其构造函数设置自定义异常类的 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的主要内容,如果未能解决你的问题,请参考以下文章