structに相当する参照のコレクションをゆるくするにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/4453749

質問

ノート: この質問は、問題についてもっと学んだので少し変わったので、それを完全に読んでください。問題がどのように発見され、最終的に解決されたかをよりよく説明しているため、元の形で残すことにしました。


私たちがC#やCLRを本当に理解していなかったときにプロジェクトの歴史の中で最も暗い深さに戻ると、私たちはタイプを作成しました、それを呼び出しましょう MyType. 。このタイプをaとして作成しました class, 、参照タイプ。

しかし、それが明らかになりました MyType a struct, 、値のタイプなので、いくつかの変更を加えてそれを行いました、そして、すべてがいつか順調でした。 MyType 値。まあ、実際には、それが参照タイプだったとき、そのコレクションは参照のコレクションでした。今、それが脱色すると、コレクションはデフォルトのコンストラクターを使用して、正常に劣ります MyType, 、その後、実際の参考文献が脱皮化されたとき、それらは孤児になり、空の値のコレクションを残します。

それで、私たちは、「タイプを参照タイプにマップしましょう、 MyTypeRef 読み込んで参照が適切に解決するようにして、実行時に使用するために実際のタイプに戻り、実行時に使用しました。教えてくれます MyTypeRef[] に変換することはできません MyType[] 間に暗黙的な変換がある場合でも MyTypeRefMyType.

だから、私たちは立ち往生しています。リファレンスタイプのコレクションとしてシリアル化されたコレクションをどのように取得できますか MyType 価値タイプのコレクションとして脱isializeする MyType?

アップデート
いくつかの調査(以下のコメントとコードを参照)は、それが新しいものの不変の性質であることを示しています MyType とその使用 ISerializable 実際の問題を引き起こしたシリアル化のために。なぜそうなるのかはまだわかりませんが、私が使用する場合 private 代わりにアクセサーを設定します ISerializable, 、 新しい MyType 古いものをロードします(に注意してください ISerializable インターフェイスはそれを使用する場合に呼び出されますが、コレクションにはデフォルト値のみが含まれています)。

いくつかのコード

// Use a List<T> in a class that also implements ISerializable and
// save an instance of that class with a BinaryFormatter (code omitted)

// Save with this one.
[Serializable]
public class MyType
{
    private string test;
    public string Test
    {
        get { return this.test; }
        set { this.test = value; }
    }

    public MyType()
    {
    }
}

// Load with this one.
[Serializable]
public class MyType : ISerializable
{
    private string test;
    public string Test
    {
        get { return this.test; }
        set { this.test = value; }
    }

    public MyType()
    {
    }

    public MyType(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("test", this.test);
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        this.test = info.GetString("test");
    }
}

ロードするとき、要素はすべてヌルであることに注意してください。削除する ISerializable 2番目の定義とロード、およびすべての動作から。変化する classstruct ロードコードでは、同じ動作が表示されます。それはまるでコレクションがセットアクセターを使用して正常に劣るだけであるかのようです。

2を更新します
だから、私は問題を見つけました(以下の私の答えを参照)が、私の質問を読んだことで答えを知っていただろうとは思えません。当時重要だとわからなかった重要な詳細を見逃しました。助けようとした人々に私の心からの謝罪。

含むロードされたコレクション MyType すぐに別のコレクションにコピーされます GetObjectData. 。以下の答えは、なぜこれが重要であることが判明したのかを説明しています。上記のサンプルコードは、完全な例を提供する必要がある追加のサンプルコードを次に示します。

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
    this.myTypeCollection = new List<MyType>();
    var loadedCollection = (List<MyType>)info.GetValue(
        "myTypeCollection",
        typeof(List<MyType>));
    this.myTypeCollection.AddRange(loadedCollection);
}
役に立ちましたか?

解決 2

私は今やや愚かに感じますが、私は問題を発見しました。追加のサンプルコードで質問を更新しました。

これがコードが行っていたことの基本です GetObjectData 方法:

  1. コレクションをロードします
  2. コレクションを別のコレクションにコピーします

これが実行時に発生したシーケンスです。

  1. コレクションはロードされましたが、要素はありません
  2. コピーnull/デフォルト要素を別のコレクションにコピーし、廃棄されたロードコレクション変数
  3. ロードされたコレクションの要素は脱色です

ポイント3の後にのみ、コレクション全体が脱色されていますが、すでにコピーを行っているため、何もありません。

修正は、を使用することでした OnDeserialized 属性 オブジェクト全体が脱必要にされたら、呼び出す方法を指定します。その後、で GetObjectData 私はロードされたコレクションへの参照を節約しますが、その内容をにコピーします OnDeserialized メソッドが完全に敏感になったら。

サイドノート
実際、すべての脱臨コードを維持するために GetObjectData, 、私はコピーを実行するために代表者を救いました、そして、私は後でそれを代表者と呼びます - そうすればそれは明らかです GetObjectData 正確に何が起こるかは脱皮化を終了します。

コード

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
    var loadedCollection = (List<MyType>)info.GetValue(
        "myTypeCollection",
        typeof(List<MyType>));

    this.myTypeCollectionLoader = () =>
    {
        this.myTypeCollection.AddRange(loadedCollection);
    };
}

[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
    this.myTypeCollectionLoader();
    this.myTypeCollectionLoader = null;
}

他のヒント

理解する必要はありませんが、保存でこれを行う場合:

[Serializable]
public class MyTypeColl
{
    public MyTypeColl()
    {
    }

    public List<MyType> Coll { get; set; }
}

[Serializable]
public class MyType
{
    private string test;
    public string Test
    {
        get { return this.test; }
        set { this.test = value; }
    }

    public MyType()
    {
    }
}

// save code

    MyTypeColl coll = new MyTypeColl();
    coll.Coll = new List<MyType>();
    coll.Coll.Add(new MyType{Test = "MyTest"});

    BinaryFormatter bf = new BinaryFormatter();
    using (FileStream stream = new FileStream("test.bin", FileMode.OpenOrCreate))
    {
        bf.Serialize(stream, coll);
    }

そしてこれはロード中です:

[Serializable]
public struct MyType
{
    private string test;
    public string Test
    {
        get { return this.test; }
        set { this.test = value; }
    }
}

// load code

    BinaryFormatter bf = new BinaryFormatter();
    using (FileStream stream = new FileStream("test.bin", FileMode.Open))
    {
        MyTypeColl coll = (MyTypeColl)bf.Deserialize(stream);
        Console.WriteLine(coll.Coll[0].Test);
    }

「mytest」が成功します。それで、私は何が欠けていますか?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top