我应该如何在自定义异常中存储数据?

时间:2009-07-08 10:29:19

标签: c# exception exception-handling

在处理自定义异常时,我通常从Exception继承,然后在我的异常类中添加一些字段/属性来存储一些额外的信息:

public class MyException : Exception
{
    public int ErrorCode{get;set;}

    public MyException()
    {}
}

在上面的示例中,ErrorCode值存储在异常中,这意味着我必须将其添加到并且如果来自受保护构造函数中的SerializationInfo对象并且被覆盖{{1}方法。

Exception类具有Data属性,根据MSDN:

  

获取键/值对的集合,提供有关异常的其他用户定义信息。

如果我将错误代码存储在GetObjectData中,它将由Exception类(根据Reflector)为我序列化,这意味着我的异常类现在看起来像:

Data

这意味着虽然在处理错误代码的获取/设置方面还有一些工作要做(比如处理转换错误和错误代码可能不在字典中的情况),但我不这样做不得不担心序列化/反序列化。

这只是实现相同目标的两种不同方式,还是一种方式比另一种方式有明显的优势(除了我已经提到过的那些)?

4 个答案:

答案 0 :(得分:5)

如果您不想创建自己的异常,则不需要Data属性。当您想在现有异常类中存储一些额外信息但不想创建自己的自定义异常类时,数据会很有用。

答案 1 :(得分:1)

Microsoft's own guidelines

  

使异常可序列化。必须序列化才能在应用程序域和远程处理边界之间正常工作。

我会将它存储在Data-property中,遗憾的是,外部代码会在未经同意的情况下修改值,或者使用解决方案1(在您的示例中),但要使其可序列化。最后我可能会选择解决方案1,因此我可以确定该值永远不会改变。

答案 2 :(得分:1)

我会避免使用数据,因为它不受您的控制,例如某些代码可能决定覆盖“ErrorCode”值。而是使用propery并实现序列化。我使用以下代码测试所有自定义异常,以确保我已正确实现它们。

public static void TestCustomException<T>() where T : Exception
{
    var t = typeof(T);

    //Custom exceptions should have the following 3 constructors
    var e1 = (T)Activator.CreateInstance(t, null);

    const string message = "message";
    var e2 = (T)Activator.CreateInstance(t, message);
    Assert.AreEqual(message, e2.Message);

    var innerEx = new Exception("inner Exception");
    var e3 = (T)Activator.CreateInstance(t, message, innerEx);
    Assert.AreEqual(message, e3.Message);
    Assert.AreEqual(innerEx, e3.InnerException);

    //They should also be serializable
    var stream = new MemoryStream();
    var formatter = new BinaryFormatter();
    formatter.Serialize(stream, e3);
    stream.Flush();
    stream.Position = 0;
    var e4 = (T)formatter.Deserialize(stream);
    Assert.AreEqual(message, e4.Message);
    Assert.AreEqual(innerEx.ToString(), e4.InnerException.ToString());
}

答案 3 :(得分:0)

你应该选择第一个解决方案。我在Data属性中看不到多少值,除非您计划引发带有附加信息的行Exception实例。

如果您有自己的异常类型,那么请改用属性:它更干净,更安全。