簡體   English   中英

使用派生類在C#中進行序列化

[英]Serialization in C# with a derived class

我正在構建一個通知框架,為此我將序列化和反序列化一個基本類,我想要發送的所有類都將從中派生。

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

System.Runtime.Serialization.SerializationException:在Assembly'Xxx.DataContract中鍵入'Xxx.DataContracts.WQAllocationUpdate',Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null'未標記為可序列化。

這是代碼:

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之前放置Serializable標志,則無法解決問題。


謝謝你的快速回答。 對不起,我忘了把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 Gravel:其實我考慮過你的建議,並創建了以下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

將[Serializable]放在課程的頂部。 Serializable不一定是AFAIK繼承的。 意思是即使基類具有[Serializable],你仍然需要它在后代類上。

我很困惑你為什么要使用BinaryFormatter和數據契約。 在這里使用DataContractSerializer是正常的...邏輯類似於使用[Serializable] ,除了你需要[DataContract ],它序列化了指定的( [DataMember] )成員,而不是BinaryFormatter使用的字段。

實際上,出於多種原因( 例如脆性 ),我建議切換到DataContractSerializer ,特別是因為這似乎是你的意圖。 或者如果你想要一個更緊湊的二進制形式, protobuf-net可能是有用的(加上也可以在平台之間移植)。

[DataContract]說一句 - 你不需要enum上的[DataContract] - 它沒有任何傷害,但也沒有做太多。

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

你派生自NotificationData,它是可序列化的嗎?

另外檢查一下:當可序列化數據類放入程序集中時,請檢查Visual Studio中的項目或文件引用,以確保獲得正確的數據類。

此外,如果您對組件進行簽名並將其放入GAC,請確保GAC中的組件是正確的! 我遇到了很多耗時的調試會話,因為我將程序集從版本1.0.0.0更新到1.0.0.1並忘記替換GAC中的舊程序集。 GAC中的程序集在本地程序集之前加載,請記住這一點。 並且...二進制格式與匯編版本有很嚴格的關系。

我創建了一個類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"); 
// -----------------------------------

更多細節可以在這里找到。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM