使用派生类在 C# 中进行序列化
-
09-09-2019 - |
题
我正在构建一个通知框架,为此我正在序列化和反序列化一个基本类,我想要发送的所有类都将从该基本类派生。
问题是代码可以编译,但是当我实际尝试序列化这个基本类时,我收到一条错误消息
System.Runtime.Serialization.SerializationException:在程序集“Xxx.DataContract,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”中键入“Xxx.DataContracts.WQAllocationUpdate”未标记为可序列化。
这是代码:
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的代码(在主帖中编辑)
我尝试将 Serialized 属性添加到两个类中,但没有成功:(
#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; }
}
}
**编辑:** 毕竟我是有罪的:) 你们都是对的。我忘记传播了 [Serializable]
属性给所有子类。更新和编译后,我不再遇到异常。谢谢你们两位的正确答案:)
@马克·砾石:实际上,我考虑了您的建议,并创建了以下 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
解决方案
把[序列化]在类的顶部。序列化不一定是继承无论是据我所知。这意味着即使该基类有[序列化],仍需要它的派生类。
其他提示
我很困惑,为什么你使用BinaryFormatter
与数据合同。这将是正常的在这里使用DataContractSerializer
...的逻辑则类似于使用[Serializable]
,除非你需要[DataContract
],并且它系列化提名([DataMember]
)的成员,而不是其BinaryFormatter
的工作原理与领域。
实际上,出于各种原因(如脆性 )我建议切换到DataContractSerializer
,尤其是这似乎是你的意图。或者,如果你想要一个更紧凑二进制形式, protobuf网可能是有用的(加是平台之间可移植的,太)。
顺便说一句 - 你不需要在[DataContract]
s的enum
- 它没有任何伤害,但不会做很多要么
要得到一类为与序列化的属性可序列化的标记,或自MarshalByRefObject衍生它。
您从NotificationData派生,它是可序列化的呢?
另外,请检查:当序列化的数据类放在一个装配检查项目或文件的引用在Visual Studio中,以确保您得到正确的一个。
此外,如果你签署组装,并把它在GAC,可以肯定的是,在GAC大会是正确的!我曾经遇到过许多耗时debugsessions因为我更新了装配从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");
// -----------------------------------
可以找到更多详细信息 这里.