在C#中,如何序列化System.Exception? (.Net CF 2.0)

时间:2008-12-23 20:51:32

标签: c# exception serialization compact-framework

我想写一个MS Message Queue的异常。当我尝试它时,我得到一个例外。所以我尝试使用仍然引发异常的XmlSerializer来简化它,但它给了我更多信息:

  

{“有反映类型的错误   'System.Exception的'。“}

使用InnerException:

  

{“无法序列化成员   System.Exception.Data类型   System.Collections.IDictionary,   因为它实现了IDictionary。“}

示例代码:

        Exception e = new Exception("Hello, world!");
        MemoryStream stream = new MemoryStream();
        XmlSerializer x = new XmlSerializer(e.GetType()); // Exception raised on this line

        x.Serialize(stream, e);
        stream.Close();

编辑: 我尽量保持这个简单,但我可能已经过头了。我想要整个位,堆栈跟踪,消息,自定义异常类型和自定义异常属性。我甚至可能想再次抛出异常。

7 个答案:

答案 0 :(得分:10)

我正在看杰森杰克逊的回答,但即使System.Exception实现了ISerializable,我对此也没有任何意义。所以我通过将异常包装在使用BinaryFormatter的类中来绕过XmlSerializer。当MS消息队列对象的XmlSerialization全部启动时,它将看到一个带有公共字节数组的类。

以下是我提出的建议:

public class WrappedException {
    public byte[] Data;

    public WrappedException() {
    }

    public WrappedException(Exception e) {
        SetException(e);
    }

    public Exception GetException() {
        Exception result;
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream stream = new MemoryStream(Data);
        result = (Exception)bf.Deserialize(stream);
        stream.Close();
        return result;
    }

    public void SetException(Exception e) {
        MemoryStream stream = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(stream, e);
        Data = stream.ToArray();
        stream.Close();
    }
}

第一次测试工作得很好,但我仍然担心自定义异常。所以我把我自己的自定义异常抛在了一起。然后我在一张空白表格上放了一个按钮。这是代码:

[Serializable]

public class MyException : Exception, ISerializable {
    public int ErrorCode = 10;
    public MyException(SerializationInfo info, StreamingContext context)
        : base(info, context) {

        ErrorCode = info.GetInt32("ErrorCode");
    }

    public MyException(string message)
        : base(message) {
    }

    #region ISerializable Members
    void ISerializable.GetObjectData(SerializationInfo info, 
        StreamingContext context) {

        base.GetObjectData(info, context);
        info.AddValue("ErrorCode", ErrorCode);
    }

    #endregion
}

private void button1_Click(object sender, EventArgs e) {
    MyException ex = new MyException("Hello, world!");
    ex.ErrorCode = 20;
    WrappedException reply = new WrappedException(ex);
    XmlSerializer x = new XmlSerializer(reply.GetType());
    MemoryStream stream = new MemoryStream();
    x.Serialize(stream, reply);
    stream.Position = 0;
    WrappedException reply2 = (WrappedException)x.Deserialize(stream);
    MyException ex2 = (MyException)reply2.GetException();
    stream.Close();
    Text = ex2.ErrorCode.ToString(); // form shows 20

    // throw ex2;

    }

虽然看起来我查找的所有其他异常类型都标有Seri​​alizableAttribute,但我必须要小心未使用SerializableAttribute标记的自定义异常。

编辑:超越自我。我没有意识到在CF上没有实现BinaryFormatter。

编辑:上面的代码片段在桌面项目中。在CF版本中,WrappedException基本上看起来一样, 只需 需要实现我自己的BinaryFormater,但我对这个建议很开心。

答案 1 :(得分:7)

我认为你基本上有两种选择:

  1. 进行自己的手动序列化(可能不想这样做)。由于您在内部异常中得到的确切消息,XML序列化肯定无法正常工作。
  2. 创建自己的自定义(可序列化)异常类,将抛出的异常数据注入自定义异常类并序列化。

答案 2 :(得分:7)

评论:

在跨进程边界进行远程处理或与系统交互时,序列化异常是一项常见任务。不要听别人说的话;他们可能从未写过远程库。

解决方案:

我之前通过创建自定义的基本异常类来检测远程执行操作。我遇到的问题是System.Exception不容易序列化,所以我不得不继承它。我处理这个问题的方法是创建自己的异常序列化(通过ISerializable),并在自定义异常中包装任何System.Exception。

在整个服务器代码中,您应该使用自定义异常,这些都可以基于您的可序列化基本类型。这项工作并不多,您将很快建立一个共同的例外库。

您写入队列(并从中读取)的图层应该执行所有异常序列化/水合作用。你可能会考虑这样的事情:

public class WireObject<T, E>
{
  public T Payload{get;set;}
  public E Exception{get;set;}
}

与队列通信的服务器和客户端层将包装您在Payload中发送的对象,或附加异常(如果有)。当从队列中消耗数据时,客户端层可以检查异常并在存在时重新抛出异常,否则将数据交给您。

这是我之前写过的一个非常简单的版本,以及我看到别人写的内容。祝你的项目好运。

答案 3 :(得分:2)

为什么呢?从消息队列中检索异常时是否实例化异常?如果没有,只需发送异常消息(作为字符串)...

答案 4 :(得分:0)

嗯,XML序列化的用途有限。例如,它无法序列化此特定方案。对于Exceptions的精确序列化和反序列化,您必须使用BinaryFormatter,只要您自己的例外标记为[Serializable],该SerializableAttribute就会起作用。所有.Net例外都标有此BinaryFormatter,这意味着它们可以使用{{1}}序列化。

但是你必须注意那里的问题 如果您的异常不可序列化,则显然会失败。但是当您的异常包含一个不可序列化的字段时,它也会失败。您应该注意确保在自定义例外中无法实现。

答案 5 :(得分:0)

我按照此link中建议的方法(向下滚动查找名为Kubilay的人发布的答案),这对我来说很有用。无需为异常对象创建任何包装类。

答案 6 :(得分:-1)

您无法将字典序列化为xml。做其他人所说的并发送信息,无论如何这都是重要的一点。