序列化异常是可抛出的

时间:2010-08-31 13:17:22

标签: c# .net exception serialization

虽然我意识到存在类似的问题(How to serialize an Exception object in C#?),虽然该页面上的答案很有帮助,但它们并没有完全解决问题或回答提出的问题。

我认为问题是如何序列化对象以允许它重建(反序列化)到同一个对象中。我试图使用davogonesAntony Booth给出的解决方案,但没有在消费方添加System.Exception基类(如:SerializationException: Exception),它是不可能将这些类型(通过它们自己)用作可以抛出的实际异常对象。

在我继续之前,让我解释一下最后的陈述。我试图在Web服务中使用Antony Booth's solution(该服务包含可序列化对象的定义),试图让所有使用者使用相同的异常(希望创建一个可重用的可序列化异常类型,而不是重新创建它过度)。

不幸的是,由于这两种类型都没有明确地派生自System.Exception,所以你不能throw它们,这显然是有用的。就像我上面提到的那样,似乎在消费端向类型类定义添加: Exception允许抛出对象,但这需要编辑自动生成的WSDL / Web服务代码,这看起来很直观/不可维护的做法(如果我错了,请纠正我)。

我的第一个问题是,是否可以序列化System.Exception或创建可以序列化的派生类型,如果可能的话,怎么会这样做呢?我应该提一下,我已经看过reconstitute the Exception object的官方方式了,但我恐怕不太理解。

我的第二个问题是关于System.Exception本身的架构。我想知道的是System.Exception类型在被记录并被明确设计为禁止您正确序列化(至少使用XML)时标记为[Serializable]的原因,因为它是{{1}对象实现Data

来自MSDN:

  

问:为什么我不能序列化哈希表?

     

答:XmlSerializer无法处理实现IDictionary接口的类。这部分是由于计划约束,部分原因是哈希表在XSD类型系统中没有对应物。唯一的解决方案是实现一个不实现IDictionary接口的自定义哈希表。

鉴于XML正在成为(如果不是已经存在)数据传输的新标准(尽管如此,微软正式推荐),不允许.NET中唯一可以抛出的对象类型似乎是非常愚蠢的XML序列化。

我期待听到所有SO'rs的一些想法(特别是因为这是我的第一篇文章)。

如果您有疑问或需要澄清,请随时告诉我。


注意:我刚刚找到了this SO post,这似乎回答了几个问题,但我想我想对此采取行动。但是,让我知道它是否太接近重复。

2 个答案:

答案 0 :(得分:2)

您可以创建一个派生自Exception的类,并通过实现ISerializable接口自行进行序列化和反序列化。

取自wrox forums的示例,继承ApplicationException

编辑:如上所述,ApplicationException已弃用。使用基类Exception类应该可以正常工作。

using System;
using System.Collections;
using System.Runtime.Serialization;

namespace Common.CustomExceptions
{

    /// <summary>
    /// Custom exception.
    /// </summary>
    [Serializable]
    public class CustomExceptionBase: ApplicationException
        {

        // Local private members
        protected DateTime _dateTime = DateTime.Now;
        protected String _machineName = Environment.MachineName;
        protected String _exceptionType = "";
        private String _exceptionDescription = "";
        protected String _stackTrace = "";
        protected String _assemblyName = "";
        protected String _messageName = "";
        protected String _messageId = "";
        protected Hashtable _data = null;
        protected String _source = "";
        protected Int32 _exceptionNumber = 0;

        public CustomExceptionBase(): base()
        {
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber): base()
        {
            this._exceptionNumber = exceptionNumber;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber, String message): base(message)
        {
            this._exceptionNumber = exceptionNumber;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber, String message, Exception innerException): 
            base(message, innerException)
        {
            this._exceptionNumber = exceptionNumber;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber, String message, Exception innerException, String messageName, String mqMessageId): 
            base(message, innerException)
        {
            this._exceptionNumber = exceptionNumber;
            this._messageId = mqMessageId;
            this._messageName = messageName;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }

        public CustomExceptionBase(Int32 exceptionNumber, String message, Exception innerException, String messageName, String mqMessageId, String source): 
            base(message, innerException)
        {
            this._exceptionNumber = exceptionNumber;
            this._messageId = mqMessageId;
            this._messageName = messageName;
            this._source = source.Equals("") ? this._source : source;
            if (Environment.StackTrace != null)
                this._stackTrace = Environment.StackTrace;
        }


        #region ISerializable members

        /// <summary>
        /// This CTor allows exceptions to be marhalled accross remoting boundaries
        /// </summary>
        /// <param name="info"></param>
        /// <param name="context"></param>
        protected CustomExceptionBase(SerializationInfo info, StreamingContext context) :
            base(info,context)
        {
            this._dateTime = info.GetDateTime("_dateTime");
            this._machineName = info.GetString("_machineName");
            this._stackTrace = info.GetString("_stackTrace");
            this._exceptionType = info.GetString("_exceptionType");
            this._assemblyName = info.GetString("_assemblyName");
            this._messageName = info.GetString("_messageName");
            this._messageId = info.GetString("_messageId");
            this._exceptionDescription = info.GetString("_exceptionDescription");
            this._data = (Hashtable)info.GetValue("_data", Type.GetType("System.Collections.Hashtable"));
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("_dateTime", this._dateTime);
            info.AddValue("_machineName", this._machineName);
            info.AddValue("_stackTrace", this._stackTrace);
            info.AddValue("_exceptionType", this._exceptionType);
            info.AddValue("_assemblyName", this._assemblyName);
            info.AddValue("_messageName", this._messageName);
            info.AddValue("_messageId", this._messageId);
            info.AddValue("_exceptionDescription", this._exceptionDescription);
            info.AddValue("_data", this._data, Type.GetType("System.Collections.Hashtable"));
            base.GetObjectData (info, context);
        }

        #endregion
    }
}

答案 1 :(得分:0)

考虑有两个班级。

第一个是可序列化的ExceptionDescription类,它必须实现您想要序列化的属性,并且从什么都不继承。第二个是CustomException,它将继承自Exception,并且只有一个ExceptionDescription实例的引用。此外,CustomException将实现“公共静态隐式运算符”,因此您可以自然地在两个实现之间移动。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Xml.Serialization;

namespace SerializableException {


public class CustomException : Exception {


    public CustomException(ExceptionDescription d) {
        this.description = d;
    }//method


    public CustomException(String message, Exception e) {
        this.description = new ExceptionDescription(message, e, 2);
    }//method

    public CustomException(String message, Exception e, int stackDepth) {
        this.description = new ExceptionDescription(message, e, stackDepth + 1);
    }//method


    public CustomException(String message, IEnumerable<Exception> causes) {
        this.description = new ExceptionDescription(message, causes, 2);
    }//method


    public CustomException(String message, IEnumerable<Exception> causes, int stackDepth) {
        this.description = new ExceptionDescription(message, causes, stackDepth + 1);
    }//method


    public CustomException(String message) {
        this.description = new ExceptionDescription(message, 2);
    }//method


    public CustomException(String message, int stackDepth) {
        this.description = new ExceptionDescription(message, stackDepth + 1);
    }//method


    public CustomException() {
    }//method


    public static CustomException newInstance(Exception e) {
        if (e == null) return null;
        if (e is CustomException) return (CustomException)e;

        CustomException output = new CustomException();
        output.description = ExceptionDescription.newInstance(e);
        return output;
    }//method


    public static implicit operator ExceptionDescription(CustomException e) {
        if (e == null) return null;
        return e.description;
    }//method

    public static implicit operator CustomException(ExceptionDescription d) {
        return d == null ? null : new CustomException(d);
    }//method


    public ExceptionDescription description;



    public String RawStackTrace {
        get { return description.RawStackTrace; }
        //set { rawStackTrace = value; }
    }//method


    public DateTime Time {
        get { return description.Time; }
    }//method

    public override String Message {
        get { return description.Message; }
    }//method


}//class




[XmlRoot]
public class ExceptionDescription {

    public ExceptionDescription() {
    }//method


    public ExceptionDescription(String message, Exception cause, int stackDepth) {
        this.Message = message;
        this.Time = DateTime.Now;
        this.RawStackTrace = new StackTrace(1 + stackDepth, true).ToString();
        this.Causes = new ExceptionDescription[] { ExceptionDescription.newInstance(cause) };
    }//method



    public ExceptionDescription(String message, IEnumerable<Exception> causes, int stackDepth) {
        this.Message = message;
        this.Time = DateTime.Now;
        this.RawStackTrace = new StackTrace(1 + stackDepth, true).ToString();
        this.Causes = (from Exception e in causes select ExceptionDescription.newInstance(e)).ToArray();
    }//method


    public ExceptionDescription(String message, int stackDepth) {
        this.Message = message;
        this.Time = DateTime.Now;
        this.RawStackTrace = new StackTrace(stackDepth + 1, true).ToString();
        this.Causes = new ExceptionDescription[0];
    }//method



    public static ExceptionDescription newInstance(Exception e) {
        if (e == null) return null;
        if (e is CustomException) return ((CustomException)e).description;

        ExceptionDescription output = new ExceptionDescription();
        output.Time = DateTime.Now;
        output.Message = e.Message;
        output.RawStackTrace = e.StackTrace;

        if (e.InnerException != null) {
            output.Causes = new ExceptionDescription[] { ExceptionDescription.newInstance(e.InnerException) };
        } else {
            output.Causes = new ExceptionDescription[0];
        }//endif
        return output;
    }//method





    public String Message;
    public ExceptionDescription[] Causes;       //MORE THAN ONE CAUSE IS LEGITIMATE             
    public String RawStackTrace;
    public DateTime Time;



}//class



}//namespace