2012-02-17 8 views
11

デシリアライズ後にプライベートリードオンリフィールドを初期化する必要があります。私はのDataContractをfolowingていますデシリアライズ後にプライベートリードオンリフィールドを初期化する

[DataContract] 
public class Item 
{ 
    public Item() 
    { 
     // Constructor not called at Deserialization 
     // because of FormatterServices.GetUninitializedObject is used 
     // so field will not be initialized by constructor at Deserialization 
     _privateReadonlyField = new object(); 
    } 

    // Initialization will not be called at Deserialization (same reason as for constructor) 
    private readonly object _privateReadonlyField = new object(); 

    [DataMember] 
    public string SomeSerializableProperty { get; set; } 

    [OnDeserializing] 
    public void OnDeserializing(StreamingContext context) 
    { 
     // With this line code even not compiles, since readonly fields can be initialized only in constructor 
     _privateReadonlyField = new object(); 
    } 
} 

私は必要なものすべてを、デシリアライズ_privateReadonlyFieldがnullでないことをした後。

これに関するお勧めはありますか? または「読み取り専用」キーを削除する必要があります。これは適切な選択肢ではありません。

+0

どのようなシリアル化方法を使用していますか?オブジェクトの構成は、さまざまな方法で異なります。 –

+0

あなたの '_privateReadonlyField'に「[DataMember]」と印を付けて間違っていますか?データ契約シリアライザは問題なく処理します。 – dasblinkenlight

+0

Joachim Isaksson:私はDataContractJsonSerializerを使用していますが、実際にはこれは問題ではありません。すべてのシリアライザはデシリアライズ時にFormatterServices.GetUninitializedObjectを使用します。 – Andris

答えて

7

private readonlyと宣言されているフィールドは、宣言された行内またはコンストラクタ内でインスタンス化できます。それが完了すると、変更することはできません。 MSDNから

読み取り専用のキーワードを使用すると、フィールドで使用できる修飾子です。フィールド宣言にreadonly修飾子が含まれている場合、宣言によって導入されたフィールドへの代入は、宣言の一部として、または同じクラスのコンストラクターでのみ発生する可能性があります。

つまり、動作させるにはreadonlyキーワードを削除する必要があります。

+0

ありがとう、Huske。残念なことに、これについて私の気持ちを承認したので、私はこの問題を解決するために何らかの方法があることを期待しました。 – Andris

8

シリアル化は、アクセシビリティルールを無視するリフレクションを使用するため、読み取り専用フィールドの値を読み取ることができます。したがって、ほとんどの場合、次のことを強く推奨するにもかかわらず、シリアライゼーションプロセスの一部として次のことが正当化されていると主張できます:

private readonly Doodad _oldField; 

[OptionalField(VersionAdded = 2)] 
private readonly Widget _newField; 

[OnDeserialized] 
private void OnDeserialized(StreamingContext context) 
{ 
    if (_oldField != null && _newField == null) 
    { 
     var field = GetType().GetField("_newField", 
      System.Reflection.BindingFlags.Instance | 
      System.Reflection.BindingFlags.DeclaredOnly | 
      System.Reflection.BindingFlags.NonPublic); 
     field.SetValue(this, new Widget(_oldField)); 
    } 
} 
+1

お返事ありがとうございます。私は本当に質問をすると、反射について忘れてしまった。 – Andris

+0

'[OptionalField]'属性はこの解決策にどのような影響を与えますか? 'OnDeserialized'はまだそれなしで動作しますか? –

+0

私が正しく覚えていれば、それを省略すると、そのフィールドを含まない入力を読み込む際に、直列化解除によって例外がスローされます。 –

関連する問題