【问题标题】:Serializing Exception to be throwable将异常序列化为可抛出
【发布时间】:2011-04-06 06:44:26
【问题描述】:

虽然我知道有一个类似的问题 (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 类型被标记为[Serializable],因为它已被记录并且显然旨在禁止您正确序列化它(至少使用XML),因为它是Data 对象实现IDictionary ?

来自MSDN:

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

答:XmlSerializer 无法处理实现 IDictionary 接口的类。这部分是由于进度限制,部分是由于哈希表在 XSD 类型系统中没有对应的事实。唯一的解决方案是实现一个不实现 IDictionary 接口的自定义哈希表。

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

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

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


注意:我刚找到this SO post,它似乎回答了一些问题,但我想我想自己动手。不过,如果它太接近重复,请告诉我。

【问题讨论】:

    标签: c# .net exception serialization


    【解决方案1】:

    您可以创建一个派生自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
        }
    }
    

    【讨论】:

    • 请注意,ApplicationException 已被弃用,应该被使用或继承。请改用Exception
    • 不幸的是,这似乎不适用于 Web 服务的上下文。我复制了您的代码并将ApplicationException 更改为Exception,我得到了与之前提到的相同的错误代码:无法序列化System.Collections.IDictionary 类型的成员System.Exception.Data,因为它实现了IDictionary。仅仅添加[Serializable] 是不够的。
    • 人力资源部。也许您可以将 _data 成员更改为不实现 IDictionary 的可序列化集合?有一些实现可以做到这一点。
    • 这个不行,因为xml序列化器和数据契约序列化器都不能序列化这个实例,所以基本不可用。
    【解决方案2】:

    考虑有两个类。

    第一个是可序列化的 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-19
      • 2021-10-19
      相关资源
      最近更新 更多