12

を含むオブジェクトをシリアライズ/デシリアライズしようとしていますDictionary<Tuid,Section>。これらは両方ともカスタム タイプです。

私のコードにDictionary<Tuid,Section>. シリアル化/逆シリアル化しようとしているのはTemplateクラスです。

このコレクションがディクショナリであるという問題を解決するためISerializableに、テンプレート クラスにインターフェイスを実装しました。

[Serializable]
public class Template : ISerializable
{
    protected Template(SerializationInfo info, StreamingContext context)
    {
        // Deserialize the sections
        List<Tuid> tuids = (List<Tuid>)info.GetValue("Sections_Keys", typeof(List<Tuid>));
        List<Section> sections = (List<Section>)info.GetValue("Sections_Values", typeof(List<Section>));
        this._sections = new Dictionary<Tuid, Section>();

        for (int i = 0; i < tuids.Count; i++)
        {
            _sections.Add(tuids[i], sections[i]);
        }           
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        List<Tuid> tuids = new List<Tuid>();
        List<Section> sections = new List<Section>();

        foreach (KeyValuePair<Tuid, Section> kvp in _sections)
        {
            tuids.Add(kvp.Key);
            sections.Add(kvp.Value);
        }

        info.AddValue("Sections_Keys", tuids, typeof(List<Tuid>));
        info.AddValue("Sections_Values", sections, typeof(List<Section>));
   }

ここでの戦略は、ディクショナリを 2 つの個別のリストに「アンパック」し、シリアル化されたストリームに個別に保存することです。その後、それらは後で再作成されます。

私のセクションクラスも実装してISerializableいます...

[Serializable]
public class Section : BaseObject
{

    protected Section(SerializationInfo info, StreamingContext context):base(.....)
    {
        // Code
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
       // code
    }
}

問題はGetObjectData()、テンプレートセクションの両方でシリアライズが呼び出されたときに、データがシリアライズ可能であり、シリアライズされていると信じさせることです。

逆シリアル化すると、テンプレートの逆シリアル化コンストラクターのみが呼び出されます。Section の逆シリアル化コンストラクターが呼び出されることはありません。この結果、 への呼び出しinfo.GetValue("Section_Values"....) List を返しますが、その中に項目が 1 つあり、その項目は null です。

セクションを逆シリアル化するコンストラクターが呼び出されないのはなぜですか? セクション内のデータの一部がシリアル化できない可能性がありますか? もしそうなら、シリアル化できないものを正確に見つける方法は?

更新:私が見つけた 1 つのことは、セクションの BaseObject が でマークされている[Serializable]が、実装していないことISerializableです。

さらに、Deserialize コードがどれほどうるさいのか疑問に思っています。基本クラスも構築するコンストラクターをターゲットにしますか?

アップデート..

わかりました、セクションのシリアライゼーションまで問題を突き止めました。コードは次のようになります...

protected Section(SerializationInfo info, StreamingContext context):base(.....)
{
    // Code
}

public void GetObjectData(SerializationInfo info, StreamingContext context)
{

    //info.AddValue("CustomObject", ClientInfo, typeof(CustomObject));
    //info.AddValue("Description", Description, typeof(string));
}

両方の行をコメントアウトすると、何もシリアル化されず、逆シリアル化コンストラクターが on で呼び出されますSection。文字列値を追加しても、すべて問題ありません。ただし、はい-ご想像のとおり-をCustomObjectシリアル化ストリームに追加すると、逆シリアル化コンストラクターは呼び出されません。

ご了承ください...

  • 私の逆シリアル化コンストラクターSectionは空のメソッドです-逆シリアル化されたデータで何もしようとしません。
  • Section の基本コンストラクターは、新しい有効なオブジェクトを渡すためにスタブ化されており、これが正常に動作することを確認しました。
  • CustomObjectをシリアル化できないことを示す例外はスローされません。
  • CustomObjectシリアル化可能であり、そのGetObjectData()メソッドは正常に実行され、逆シリアル化で正常に構築されます。

このシリアライズ可能なオブジェクトを純粋にストリームに追加するだけで、フレームワークがデシリアライザ コンストラクタに失敗するのは奇妙に思えますSection

なぜこれが起こっているのでしょうか?

4

2 に答える 2

13

オプションの1つは実装することです

[OnDeserializing]
void OnDeserializing(StreamingContext c)
{
    //create what is required here
}

Templateデフォルトのシリアライザーは子オブジェクトのコンストラクターを呼び出さないため、クラス内 -Sectionクラス

于 2011-12-01T11:06:07.033 に答える
2

あなたの問題は、シリアライゼーションの仕組みが原因だと思います(深さではなく幅が最初であることを思い出したようです)。これが意味することは、テンプレートを逆シリアル化し、そこにスペースを作成してセクションを追加することです。

ただし、これらのセクションはまだシリアル化解除されていないため、テンプレートのシリアル化解除が完了した後にシリアル化解除されます。ブレークポイントを使用してコードをさらに実行させることで、これを確認できるはずです。これを修正する方法は、oleksii のソリューションか、同様に IDeserializationCallback を使用することです。

IDeserializationCallback とは、インスタンスが逆シリアル化 (およびそのメンバー) を完了すると、メソッドを呼び出して、いくつかのワイヤリングを実行できるようにすることです。以下のようなものをもっと試してみます:

[Serializable]
public class Template : ISerializable, IDeserializationCallback
{
    private List<Tuid> tuids;
    private List<Section> sections
    protected Template(SerializationInfo info, StreamingContext context)
    {
        tuids = (List<Tuid>)info.GetValue("Sections_Keys", typeof(List<Tuid>));
        sections = (List<Section>)info.GetValue("Sections_Values", typeof(List<Section>));
        this._sections = new Dictionary<Tuid, Section>();
    }

    public void OnDeserialization(object sender)
    {
        // Section serialization constructor should have been called by this point
        for (int i = 0; i < tuids.Count; i++)
        {
            _sections.Add(tuids[i], sections[i]);
        } 
    }
}
于 2011-12-01T11:26:52.817 に答える