使用派生类在C#中进行序列化
我正在构建一个通知框架,为此我正在序列化和反序列化一个基本类,我要发送的所有类都将从中派生 问题是代码是可以编译的,但是当我实际尝试序列化这个基本类时,我得到一个错误 System.Runtime.Serialization.SerializationException:程序集“Xxx.DataContracts,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”中的类型“Xxx.DataContracts.WQAllocationUpdate”未标记为可序列化 代码如下:使用派生类在C#中进行序列化,c#,serialization,derived-class,C#,Serialization,Derived Class,我正在构建一个通知框架,为此我正在序列化和反序列化一个基本类,我要发送的所有类都将从中派生 问题是代码是可以编译的,但是当我实际尝试序列化这个基本类时,我得到一个错误 System.Runtime.Serialization.SerializationException:程序集“Xxx.DataContracts,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”中的类型“Xxx.DataContracts.WQAllocationUpdat
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,
}
我得到了以下错误:
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
如果我将Serializable标志放在DataContract
之前,则无法解决问题
谢谢你的快速回答。 很抱歉,我忘了把通知数据的代码放进去(在主帖子中编辑) 我尝试将Serializable属性放入这两个类,但均未成功:( **编辑:*毕竟我有罪:)你们都是对的。 我忘记将
[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
#区域数据序列化程序
///
///为提供的类型创建数据协定序列化程序。类型必须标记为
///要成功序列化的数据协定属性。
///
///要序列化的类型
///数据协定序列化程序
公共静态DataContractSerializer CreateDataContractSerializer(),其中T:class
{
DataContractSerializer serializer=新的DataContractSerializer(typeof(T));
返回序列化程序;
}
#端区
要获取可序列化的类,请使用serializable属性对其进行标记,或从MarshallByRefObject派生该类
您从NotificationData派生,那么它可以序列化吗
还要检查:当可序列化数据类放入程序集中时,请在VisualStudio中检查项目或文件引用,以确保获得正确的引用
此外,如果您在程序集上签名并将其放入GAC,请确保GAC中的程序集是正确的!我遇到了许多耗时的调试会话,因为我将程序集从版本1.0.0.0更新到了版本1.0.0.1,并且忘记在GAC中替换旧的程序集。请记住,GAC中的程序集是在本地程序集之前加载的。而且。。。二进制格式对于程序集版本非常严格。将[Serializable]放在类的顶部。Serializable也不一定是AFAIK继承的。这意味着,即使基类具有[Serializable],您仍然需要在子类上使用它。我很不明白为什么要将
BinaryFormatter
与数据协定一起使用。在这里使用DataContractSerializer
是正常的。。。然后,该逻辑类似于使用[Serializable]
,只是您需要[DataContract
],它序列化指定的([DataMember]
)成员,而不是BinaryFormatter
使用的字段
实际上,出于许多原因()我建议切换到DataContractSerializer
,尤其是因为这似乎是您的意图。或者,如果您想要更紧凑的二进制格式,可能会很有用(此外,还可以在平台之间移植)
顺便说一句-您不需要
enum
s上的[DataContract]
-它没有坏处,但也没有太多作用。我创建了一个类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");
// -----------------------------------
AA D1=新的AA()//派生类型
BB D2=新的BB()//派生类型
CC D3=新的CC()//派生类型
X D4=新的X()//基类
XList AllData=new XList();
所有数据。添加(D1);
添加所有数据(D2);
添加所有数据(D3);
添加所有数据(D4);
// -----------------------------------
保存(@“C:\Temp\Demo.xml”);
// -----------------------------------
//从XML文件检索数据
// -----------------------------------
XList AllData=new XList();
打开(@“C:\Temp\Demo.xml”);
// -----------------------------------
可以找到更多详细信息。我很困惑为什么要将BinaryFormatter与数据契约一起使用(此评论现在扩展为答案)。Marc是正确的。使用DataContractSerializer。它还允许您以二进制形式序列化。下面是一些代码:using(var fs=newfilestream(FILE_NAME,FileMode.Create,FileAccess.Write)){using(var reader=XmlDictionaryWriter.CreateBinaryWriter(fs)){var dcs=newDataContractSerializer(typeof(NotificationData));dcs.WriteObject(reader,true); } }
#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; }
}
}
#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
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");
// -----------------------------------