使用派生类在 C# 中进行序列化
我正在构建一个通知框架,为此我正在序列化和反序列化一个基本类,我想要发送的所有类都将从该基本类派生。
问题是代码可以编译,但是当我实际尝试序列化这个基本类时,我收到一条错误消息
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; }
}
}
**编辑:** Mea culpa 毕竟:) 你们都是对的。 我忘记将 [Serialized]
属性传播到所有子类。 更新和编译后,我不再遇到异常。 谢谢你们的正确答案:)
@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
I'm building a notification framework and for that I'm serializing and deserializing a basic class, from which all the classes I want to send will derive.
The problem is that the code compiles, but when I actually try to serialize this basic class I get an error saying
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.
Here is the code :
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; }
}
}
The DataContract
for the Notification is:
/// <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,
}
The code used to serialize the data is:
#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
When I try to create a message:
WCallUpdate m_wCallUpdate = new WCallUpdate();
NotificationTypeKey m_notificationTypeKey = new NotificationTypeKey.Default;
CreateMessage(notificationTypeKey , wCallUpdate );
I got the following error:
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
If I put the Serializable flag before the DataContract
one does not solve the problem.
thank you for the fast answer.
Sorry that i forgot to put the code of the NotificationData (edited in the main post)
I tried putting the Serializable attribute to both class without success :(
#region NotificationData
/// <summary>
/// Basic class used in the notification service
/// </summary>
[Serializable]
[DataContract]
public class NotificationData
{
}
#endregion
and
[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; }
}
}
**Edit: ** Mea culpa afterall :) You were both right.
I forgot to spread the [Serializable]
Attribute to all the child class.
After updating and compiling, i got no longer the exception.
thank you both for your correct answers :)
@Marc Gravel:
Actually i thought about what you are suggesting, and created the following DataContractSerializer, but I'm not sure this will work? As my classes use other classes? the big problem with the DataContractSerializer is that you need to specify the type of the object you want to serialize, and as my class uses other class as private fields, that might cause a problem right?
#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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
将 [Serialized] 放在类的顶部。 据我所知,可序列化不一定是继承的。 这意味着即使基类具有 [Serialized],您仍然需要在后代类上使用它。
put [Serializable] at the top of the class. Serializable isn't necessarily inherited either AFAIK. meaning even if the base class has [Serializable], you still need it on the descendent class.
我很困惑为什么您将
BinaryFormatter
与数据契约一起使用。 在这里使用DataContractSerializer
是正常的...逻辑类似于使用[Serialized]
,只不过您需要[DataContract
],并且它序列化指定的 ([DataMember]
) 成员,而不是BinaryFormatter
使用的字段。实际上,由于多种原因(例如脆性)我会建议切换到 DataContractSerializer,尤其是因为这似乎是您的意图。 或者,如果您想要更紧凑的二进制形式,protobuf-net 可能会很有用( plus 也可以在平台之间移植)。
顺便说一句 - 您不需要
enum
上的[DataContract]
- 它没有任何害处,但也没有做太多事情。I'm very confused why you're using
BinaryFormatter
with a data-contract. It would be normal to useDataContractSerializer
here... the logic is then similar to using[Serializable]
, except you need[DataContract
], and it serializes the nominated ([DataMember]
) members, rather than the fields whichBinaryFormatter
works with.Actually, for numerous reasons (such as brittleness) I would suggest switching to
DataContractSerializer
, especially as that seems to be your intention. Or if you want a more compact binary form, protobuf-net may be useful (plus is portable between platforms, too).As an aside - you don't need the
[DataContract]
onenum
s - it does no harm, but doesn't do a lot either.要使类可序列化,请使用可序列化属性对其进行标记或从 MarshalByRefObject 派生它。
您从NotificationData派生,那么它可以序列化吗?
另请检查这一点:将可序列化数据类放入程序集中时,请检查 Visual Studio 中的项目或文件引用,以确保获得正确的项目或文件引用。
另外,如果您签署程序集并将其放入 GAC 中,请确保 GAC 中的程序集是正确的! 我遇到过许多耗时的调试会话,因为我将程序集从版本 1.0.0.0 更新到了 1.0.0.1,却忘记替换 GAC 中的旧版本。 GAC 中的程序集先于本地程序集加载,请记住这一点。 而且...二进制格式与汇编版本非常严格。
To get a class to be serializable mark it with the serializable attribute or derived it from MarshalByRefObject.
You derive from NotificationData, is it serializable then?
Also check this: when serializable data classes are put in an assembly check your project or file reference in Visual Studio to be sure you get the right one.
Also if you sign the assembly and put it in the GAC, be sure that the assembly in the GAC is the right one! I have encountered many time consuming debugsessions because I updated the assembly from version 1.0.0.0 to 1.0.0.1 and forgot to replace the old one in the GAC. Assemblies in the GAC are loaded prior the local assemblies, keep that in mind. And... binary formatting is very strict related to assembly versions.
我创建了一个类 XList 来完成此操作:
可以找到更多详细信息 此处。
I have created a class XList to accomplish this:
More details can be found here.