2010-08-31 88 views
8

虽然我意识到有类似的问题(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),因为它的对象实现IDictionary对象实现了Data

MSDN:

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

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

由于XML正在成为(如果不是已经是)进行数据传输(由微软,但是官方推荐)的新标准,它似乎荒谬愚蠢的,不允许在.NET中的唯一对象类型,可以是抛出不是XML可序列化的。

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

如果您有任何问题或需要澄清,请不要犹豫,让我知道。


注:我刚刚发现this SO post,这似乎回答几个问题,但我想我愿意把我自己捶它。尽管如此,让我知道它是否太接近重复。

回答

1

您可以创建一个从Exception派生的类,并通过实现ISerializable接口自己完成序列化和反序列化。从wrox forums采取

实施例,子类ApplicationException

EDIT:作为指出,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

只是一个简短的提示'ApplicationException'已被弃用,应该_not_被使用或子类。改用'Exception'。 – thecoop 2010-08-31 13:44:34

+0

不幸的是,这似乎不适用于Web服务的上下文中。我复制了你的代码,并将'ApplicationException'改为'Exception',并且得到了我之前提到的相同的错误代码: 无法序列化System.Collections.IDictionary类型的成员System.Exception.Data,因为它实现IDictionary的。 只需添加'[Serializable]'是不够的。 – llaughlin 2010-08-31 14:16:31

+0

Hrm。也许你可以将_data成员更改为不能实现IDictionary的可序列化集合?这里有一些实现。 – 2010-09-01 07:04:29

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