1

バージョントレラントなシリアル化をサポートするクラスがあります

[Serializable]
class A {
    [OptionalField]
    int a;

    [OptionalField]
    MyClass b;

    [OptionalField]
    MyClass c;
}
  • デシリアライズ後に欠落しているフィールドを修正するにはどうすればよいですか?おそらく、でマークされたメソッドを使用する必要があり[OnDeserializing]ます。しかし、どのフィールドが無視されたかをどのように取得できますか?
  • フィールドが欠落している場合にデフォルトのコンストラクターでフィールドを初期化するように自動逆シリアル化を構成できますか?
4

2 に答える 2

3

さらに、OnSerializingAttributeおよびOnSerializedAttributeを使用してフィールドを設定できます。例が示すように、すでに設定されているフィールドはその値を保持します。ただし、これは、OnSerializingイベント中にフィールドが設定された場合にのみ当てはまることに注意してください。OnSerializedイベント中に設定されたフィールドは、シリアル化された値をオーバーライドします。

編集:この場合、フィールドがnullに等しいかどうかをメソッド(OnSerializedで装飾)でチェックインし、必要に応じてインスタンス化できます。このフィールドが使用されない可能性があり、その作成を延期できる可能性がある場合は、問題のフィールドをプロパティの背後に隠して、遅延してインスタンス化することを検討してください。

Models.cs:

using System;
using System.Runtime.Serialization;

namespace SerializationExample
{
    [Serializable]
    public class Model
    {
        public Model(){
            A = new SomeClass();
        }

        [OptionalField]
        public int value;

        [OptionalField]
        public SomeClass A;

        [OptionalField]
        public AnotherClass B;            

        [OnDeserializing]
        void OnDeserializing(StreamingContext context)
        {
            B = new AnotherClass("Set during deserializing");
        }

        [OnDeserialized]
        void OnDeserialized(StreamingContext context)
        {
            // Do sth. here after the object has been deserialized
        }

        public override string ToString()
        {
            return String.Format("A: {0}\nB: {1}", A, B);
        }

    }

    [Serializable]
    public class SomeClass
    {
        public string Value { get; set; }

        public SomeClass()
        {
            Value = "Default";
        }

        public override string ToString()
        {
            return Value;
        }
    }

    [Serializable]
    public class AnotherClass
    {
        public string Value { get; private set; }

        public AnotherClass(string v)
        {
            Value = v;
        }

        public override string ToString()
        {
            return Value;
        }
    }
}

Program.cs:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace SerializationExample
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] FileNames = new string[] {
                @"model1.bin",
                @"model2.bin"
            };

            Stream[] files = new Stream[] {
                File.Create(FileNames[0]),
                File.Create(FileNames[1])
            };

            BinaryFormatter bf = new BinaryFormatter();

            Model m1 = new Model();
            m1.B = new AnotherClass("Set in app");
            m1.A.Value = "Set in app";

            Model m2 = new Model();

            Console.WriteLine("M1:\n{0}\n", m1);
            Console.WriteLine("M2:\n{0}\n\n", m2);

            bf.Serialize(files[0], m1);
            bf.Serialize(files[1], m2);

            foreach (var f in files)
                f.Seek(0, SeekOrigin.Begin);

            m1 = null;
            m2 = null;

            m1 = (Model)bf.Deserialize(files[0]);
            m2 = (Model)bf.Deserialize(files[1]);

            Console.WriteLine("M1:\n{0}\n", m1);
            Console.WriteLine("M2:\n{0}\n\n", m2);

            foreach (var f in files)
                f.Close();           
        }
    }
}

出力:

M1:
A: Set in app
B: Set in app

M2:
A: Default
B:


M1:
A: Set in app
B: Set in app

M2:
A: Default
B: Set during deserializing
于 2012-08-31T21:26:30.390 に答える
0

これらの値をデフォルトに初期化するだけの場合、必要なのは、それらを初期化するデフォルトのパラメーターなしのコンストラクターだけです。これは逆シリアル化中に呼び出され、欠落しているフィールドは、コンストラクターで初期化した値を保持します。

より詳細な制御が必要な場合は、クラスにインターフェイスと適切なコンストラクターを実装できISerializableます(通常は両方を実行する必要がありますが、どちらか一方が不要な場合がよくあります)。

C#が署名付きのコンストラクターを見つけた場合:

protected A ( SerializationInfo info, StreamingContext context )
{
}

そのコンストラクターを呼び出し、弱い型の辞書にすべてのシリアル化情報を渡します。(を使用ISerializable::GetObjectDataして、カスタムフィールドをオブジェクトに書き込み、コンストラクターで取得できます)。メソッドを使用して、info.GetXXXこれらの値を抽出できます。

注意すべき点の1つは、このコンストラクターを実装する場合、通常は自動的に逆シリアル化されるフィールドを含め、すべての作業を実行する必要があるということです。不足しているフィールドについては、適切に設定してください。同様に、を実装する場合は、そのメソッドのすべてGetObjectDataをシリアル化する必要があります。非常に簡単ですが、クラスを変更する場合は、カスタムメソッド/コンストラクターを適切に編集する必要があります。

于 2012-08-31T20:55:53.513 に答える