2010-08-31 56 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