2009-04-16 85 views
4

我正在構建一個通知框架,並且我正在序列化和反序列化一個基類,從中我要發送所有的類。C#中的派生類的序列化

的問題是,代碼編譯,但是當我真正嘗試序列化這個基本類我得到一個錯誤說

System.Runtime.Serialization.SerializationException: Type 'Xxx.DataContracts.WQAllocationUpdate' in Assembly 'Xxx.DataContract, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.

下面是代碼:

public class WCallUpdate : NotificationData 
{ 
    private string m_from = ""; 
    [DataMember] 
    public string From 
    { 
     get { return m_from; } 
     set { m_from = value; } 
    } 
    private WCall m_wCall = new WCall(); 
    [DataMember] 
    public WCall Call 
    { 
     get { return m_wCall; } 
     set { m_wCall = value; } 
    } 
} 

DataContract爲通知是:

/// <summary> 
/// Basic class used in the notification service 
/// </summary> 
[DataContract] 
public class NotificationData 
{ 
} 

/// <summary> 
/// Enum containing all the events used in the application 
/// </summary> 
[DataContract] 
public enum NotificationTypeKey 
{ 
    [EnumMember] 
    Default = 0, 
    [EnumMember] 
    IWorkQueueServiceAttributionAddedEvent = 1, 
    [EnumMember] 
    IWorkQueueServiceAttributionUpdatedEvent = 2, 
    [EnumMember] 
    IWorkQueueServiceAttributionRemovedEvent = 3, 
} 

用於序列化數據的代碼是:

#region Create Message 
    /// <summary> 
    /// Creates a memoryStream from a notificationData 
    /// note: we insert also the notificationTypeKey at the beginning of the 
    /// stream in order to treat the memoryStream correctly on the client side 
    /// </summary> 
    /// <param name="notificationTypeKey"></param> 
    /// <param name="notificationData"></param> 
    /// <returns></returns> 
    public MemoryStream CreateMessage(NotificationTypeKey notificationTypeKey, NotificationData notificationData) 
    { 
     MemoryStream stream = new MemoryStream(); 
     BinaryFormatter formatter = new BinaryFormatter(); 
     try 
     { 
      formatter.Serialize(stream, notificationTypeKey); 
      formatter.Serialize(stream, notificationData); 
     } 
     catch (Exception ex) 
     { 
      Logger.Exception(ex); 
     } 
     return stream; 
    } 
    #endregion 

當我試圖創建一個消息:

WCallUpdate m_wCallUpdate = new WCallUpdate(); 
NotificationTypeKey m_notificationTypeKey = new NotificationTypeKey.Default; 
CreateMessage(notificationTypeKey , wCallUpdate); 

我得到了以下錯誤:

System.Runtime.Serialization.SerializationException: Type 'Xxx.DataContracts.WCall' in Assembly 'Xxx.DataContract, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable. 
    at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) 
    at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) 
    at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() 
    at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) 
    at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) 
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo) 
    at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) 
    at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) 
    at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph) 
    at Xxx.Notification.NotificationMessageFactory.CreateMessage(NotificationTypeKey notificationTypeKey, NotificationData notificationData) in Xxx.Notification\NotificationCenter.cs:line 36 

如果我把序列化的標誌前DataContract一個沒有解決的問題。


謝謝你的快速回答。 對不起,我忘了把NotificationData的代碼(在主後編輯)

我試圖把Serializable屬性這兩個類都沒有成功:(

#region NotificationData 
/// <summary> 
/// Basic class used in the notification service 
/// </summary> 
[Serializable] 
[DataContract] 
public class NotificationData 
{ 
} 
#endregion 

[Serializable] 
public class WCallUpdate : NotificationData 
{ 
    private string m_from = ""; 
    [DataMember] 
    public string From 
    { 
     get { return m_from; } 
     set { m_from = value; } 
    } 
    private WCall m_wCall = new WCall(); 
    [DataMember] 
    public WCall Call 
    { 
     get { return m_wCall; } 
     set { m_wCall = value; } 
    } 
} 

**編輯:** Mea culpa afterall :)你們都是對的。 我忘了把[Serializable]屬性傳給所有的孩子。 更新和編譯後,我不再有例外。 感謝你們爲您的正確答案:)


@Marc碎石: 其實我想過,你的建議是什麼,並創建了以下DataContractSerializer的,但我不知道這是否行得通呢?當我的課程使用其他課程? DataContractSerializer的最大問題是您需要指定要序列化的對象的類型,並且由於我的類將其他類用作專用字段,這可能會導致問題。

#region DataContractSerializer 
     /// <summary> 
     /// Creates a Data Contract Serializer for the provided type. The type must be marked with 
     /// the data contract attribute to be serialized successfully. 
     /// </summary> 
     /// <typeparam name="T">The type to be serialized</typeparam> 
     /// <returns>A data contract serializer</returns> 
     public static DataContractSerializer CreateDataContractSerializer<T>() where T : class 
     { 
      DataContractSerializer serializer = new DataContractSerializer(typeof(T)); 
      return serializer; 
     } 
     #endregion 
+0

我很困惑你爲什麼使用BinaryFormatter和數據契約(這個評論現在擴展到了答案中)。 – 2009-04-16 07:11:28

回答

18

將[Serializable]放在類的頂部。可序列化不一定會繼承AFAIK。即使基類具有[Serializable],您仍然需要它在後代類上。

2

要獲得可序列化的類,請使用serializable屬性標記它,或者從MarshalByRefObject派生它。

您從NotificationData派生出來,它是可序列化的嗎?

此外,請檢查以下內容:將可序列化數據類放入程序集時,請在Visual Studio中檢查項目或文件引用,以確保獲得正確的結果。

此外,如果您簽署該程序集並將其放入GAC,請確保GAC中的程序集是正確的!我遇到了很多耗時的debugsessions,因爲我將程序集從版本1.0.0.0更新到1.0.0.1,並忘記在GAC中替換舊版本。 GAC中的程序集在本地程序集之前加載,請牢記這一點。而且...二進制格式化與組裝版本非常嚴格相關。

6

我很困惑你爲什麼使用BinaryFormatter與數據契約。這裏使用DataContractSerializer是正常的,這裏的邏輯與使用[Serializable]相似,除了你需要[DataContract],它將序列化提名的([DataMember])成員,而不是BinaryFormatter協同工作的字段。

其實,由於很多原因(such as brittleness),我建議切換到DataContractSerializer,尤其是因爲這似乎是你的意圖。或者如果你想要一個更緊湊的二進制形式,protobuf-net可能是有用的(加上也可以在平臺之間移植)。

順便說一句 - 你不需要上的[DataContract] - 它沒有任何壞處,但也沒有太大的作用。

+0

Marc是正確的。使用DataContractSerializer。它將允許你以二進制序列化。 下面是一些代碼: 使用(VAR FS =新的FileStream(FILE_NAME,FileMode.Create,FileAccess.Write)) { 使用(VAR讀者= XmlDictionaryWriter.CreateBinaryWriter(FS)) { 變種DCS =新的DataContractSerializer (typeof運算(NotificationData)); dcs.WriteObject(reader,true); } } – CodeWarrior 2009-07-22 16:23:02

0

我創建了一個類的Xlist做到這一點:

AA D1=new AA(); //Derived type 
BB D2=new BB(); //Derived type 
CC D3=new CC(); //Derived type 
X D4=new X(); //Base Class 

XList<X> AllData=new XList<X>(); 
AllData.Add(D1); 
AllData.Add(D2); 
AllData.Add(D3); 
AllData.Add(D4); 
// ----------------------------------- 
AllData.Save(@"C:\Temp\Demo.xml"); 
// ----------------------------------- 
// Retrieve data from XML file 
// ----------------------------------- 
XList<X> AllData=new XList<X>(); 
AllData.Open(@"C:\Temp\Demo.xml"); 
// ----------------------------------- 

更多細節可以發現here