2012-02-17 9 views
11

Potrzebuję zainicjować prywatne pole readonly po Deserializacji. Mam folowing DataContract:Inicjuj prywatne pola readonly po Deserializowaniu

[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(); 
    } 
} 

Wszystko co muszę, że po Deserializacji _privateReadonlyField nie jest null.

Wszelkie sugestie na ten temat - czy to w ogóle możliwe? Lub muszę usunąć "tylko do odczytu" klucz, który nie jest dobrym rozwiązaniem.

+0

Jakie metody serializacji używasz? Konstrukcja obiektów różni się dla różnych metod. –

+0

Co jest nie tak z oznaczeniem '_privateReadonlyField' a' [DataMember] '? Serializator kontraktu danych zajmie się tym bez problemu. – dasblinkenlight

+0

Joachim Isaksson: Używam DataContractJsonSerializer, ale tak naprawdę to nie ma znaczenia - wszystkie Serializatory używają FormatterServices.GetUninitializedObject podczas Deserializacji. – Andris

Odpowiedz

7

Każde pole zadeklarowane jako private readonly może być utworzone w tym samym wierszu, w którym zostało zadeklarowane lub wewnątrz konstruktora. Po wykonaniu tej czynności nie można tego zmienić.

Od MSDN:

tylko do odczytu słowo kluczowe jest modyfikator, które można stosować na polach. Gdy deklaracja pola zawiera modyfikator tylko do odczytu, przypisania do pól wprowadzonych przez deklarację mogą wystąpić tylko jako część deklaracji lub w konstruktorze w tej samej klasie.

Oznacza to, że trzeba będzie usunąć słowo kluczowe readonly, aby mogło działać.

+0

Dzięki, Huske. Niestety wyraziłeś zgodę na to, miałem nadzieję, że istnieje jakiś sposób rozwiązania tego problemu. – Andris

8

Serializacja jest w stanie odczytać wartości dla pól tylko do odczytu, ponieważ wykorzystuje odbicie, które ignoruje reguły dostępności. Można argumentować, że po to, zatem uzasadnione jako część procesu serializacji, choć ja polecam zdecydowanie przeciwko nim w niemal każdej innej sytuacji:

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

Dzięki za odpowiedź. Naprawdę zapomniałem o refleksji, kiedy zadałem to pytanie. – Andris

+0

Jaki wpływ ma na to rozwiązanie atrybut "[Opcjonalnie]? Czy 'OnDeserialized' nadal działa bez niego? –

+0

Jeśli dobrze pamiętam, pomijanie go spowoduje, że deserializacja wygeneruje wyjątek podczas odczytu danych wejściowych, które nie zawierają tego pola. –