[英]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.