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

adr*_*nks 5 c# exception-handling exception

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

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

    public MyException()
    {}
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,该ErrorCode值存储在异常中,这意味着我必须将其添加到并且如果从SerializationInfo受保护的构造函数中的对象和重写的GetObjectData方法中退出.

异常类具有数据属性,它根据MSDN:

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

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

public class MyException : Exception
{
    public int ErrorCode
    {
        get {return (int) Data["ErrorCode"];}
        set {Data["ErrorCode"] = value;}
    }

    public MyException()
    {}
}
Run Code Online (Sandbox Code Playgroud)

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

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

Ric*_*ton 5

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


Mat*_*lls 2

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

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());
}
Run Code Online (Sandbox Code Playgroud)