2009-04-16 16 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通知は:

データのシリアル化に使用されるコードは次のとおりです。

#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); 

I、次のエラーを得た:

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 1で問題が解決しない前に、私は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砂利: 実際に私は、あなたが示唆されているかについて考え、そして次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を使用しています(このコメントは答えに展開されています)。 –

答えて

18

クラスの先頭に[Serializable]を挿入します。シリアライズ可能なものは必ずしもAFAIKのいずれかに継承されません。つまり、基底クラスに[Serializable]があっても、子孫クラスでそれが必要です。

2

クラスをシリアライズ可能にするには、シリアライズ可能属性でマークするか、MarshalByRefObjectから派生させます。

NotificationDataから派生していますが、それは次にシリアル化できますか?

また、シリアライズ可能なデータクラスをアセンブリに配置するときは、Visual Studioでプロジェクトまたはファイル参照をチェックして、正しいものを取得するようにしてください。

また、アセンブリに署名してGACに入れる場合は、GACのアセンブリが正しいかどうかを確認してください。バージョン1.0.0.0から1.0.0.1にアセンブリを更新し、GACで古いものを置き換えるのを忘れていたので、多くの時間を浪費するデバッグセッションが発生しました。 GACのアセンブリは、ローカルアセンブリの前にロードされます。そのことを念頭に置いてください。そして...バイナリフォーマットは、アセンブリバージョンに関連して非常に厳格です。

6

なぜ私はBinaryFormatterをデータ契約で使用しているのかと非常に混同しています。 DataContractSerializerを使用するのが普通です...ロジックは[DataContractが必要であることを除いて[Serializable]を使用するのと似ており、BinaryFormatterが動作するフィールドではなく、指定された([DataMember])メンバをシリアル化します。

実際、多くの理由(such as brittleness)のために、私はDataContractSerializerに切り替えることをお勧めします。特にあなたの意志であるようです。よりコンパクトなバイナリ形式が必要な場合は、protobuf-netが便利です(また、プラットフォーム間でも移植可能です)。

脇に - enum[DataContract]は必要ありません。害はありませんが、それほど多くはありません。

+0

マークが正しいです。 DataContractSerializerを使用します。バイナリでもシリアライズすることができます。 ここにいくつかのコードは:(VARリーダ= XmlDictionaryWriter.CreateBinaryWriter(FS))を用いて (VARのFS =新規のFileStream(FILE_NAME、FileMode.Create、FileAccess.Write))を使用して { { VARのDCS =新しいDataContractSerializerは(typeof(NotificationData)); dcs.WriteObject(reader、true); } } – CodeWarrior

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を見つけることができます。

関連する問題