2009-04-16 128 views
4

我正在构建一个通知框架,并且我正在序列化和反序列化一个基类,从中我要发送所有的类。C#中的派生类的序列化

的问题是,代码编译,但是当我真正尝试序列化这个基本类我得到一个错误说

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.

下面是代码:

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的代码(在主后编辑)

我试图把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碎石: 其实我想过,你的建议是什么,并创建了以下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 
+0

我很困惑你为什么使用BinaryFormatter和数据契约(这个评论现在扩展到了答案中)。 – 2009-04-16 07:11:28

回答

18

将[Serializable]放在类的顶部。可序列化不一定会继承AFAIK。即使基类具有[Serializable],您仍然需要它在后代类上。

2

要获得可序列化的类,请使用serializable属性标记它,或者从MarshalByRefObject派生它。

您从NotificationData派生出来,它是可序列化的吗?

此外,请检查以下内容:将可序列化数据类放入程序集时,请在Visual Studio中检查项目或文件引用,以确保获得正确的结果。

此外,如果您签署该程序集并将其放入GAC,请确保GAC中的程序集是正确的!我遇到了很多耗时的debugsessions,因为我将程序集从版本1.0.0.0更新到1.0.0.1,并忘记在GAC中替换旧版本。 GAC中的程序集在本地程序集之前加载,请牢记这一点。而且...二进制格式化与组装版本非常严格相关。

6

我很困惑你为什么使用BinaryFormatter与数据契约。这里使用DataContractSerializer是正常的,这里的逻辑与使用[Serializable]相似,除了你需要[DataContract],它将序列化提名的([DataMember])成员,而不是BinaryFormatter协同工作的字段。

其实,由于很多原因(such as brittleness),我建议切换到DataContractSerializer,尤其是因为这似乎是你的意图。或者如果你想要一个更紧凑的二进制形式,protobuf-net可能是有用的(加上也可以在平台之间移植)。

顺便说一句 - 你不需要上的[DataContract] - 它没有任何坏处,但也没有太大的作用。

+0

Marc是正确的。使用DataContractSerializer。它将允许你以二进制序列化。 下面是一些代码: 使用(VAR FS =新的FileStream(FILE_NAME,FileMode.Create,FileAccess.Write)) { 使用(VAR读者= XmlDictionaryWriter.CreateBinaryWriter(FS)) { 变种DCS =新的DataContractSerializer (typeof运算(NotificationData)); dcs.WriteObject(reader,true); } } – CodeWarrior 2009-07-22 16:23:02

0

我创建了一个类的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"); 
// ----------------------------------- 

更多细节可以发现here