虽然我意识到存在类似的问题(How to serialize an Exception object in C#?),虽然该页面上的答案很有帮助,但它们并没有完全解决问题或回答提出的问题。
我认为问题是如何序列化对象以允许它重建(反序列化)到同一个对象中。我试图使用davogones和Antony 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,这似乎回答了几个问题,但我想我想对此采取行动。但是,让我知道它是否太接近重复。
答案 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