2012-02-17 2 views
11

Мне нужно инициализировать личное поле readonly после Deserialization. Я folowing DataContract:Инициализировать приватные поля readonly после Deserializing

[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 не является нулевым.

Любые предложения об этом - возможно ли вообще? Или мне нужно удалить ключ «readonly», что не является хорошим вариантом.

+0

Какой метод сериализации вы используете? Конструкция объектов различна для разных методов. –

+0

Что случилось с маркировкой вашего '_privateReadonlyField'' '[DataMember]'? Сериализатор данных может позаботиться об этом без проблем. – dasblinkenlight

+0

Joachim Isaksson: Я использую DataContractJsonSerializer, но на самом деле это не имеет значения - все сериализаторы используют FormatterServices.GetUninitializedObject при десериализации. – Andris

ответ

7

Любое поле, объявленное как private readonly, может быть создано в той же строке, где оно было объявлено или внутри конструктора. Как только это будет сделано, его нельзя будет изменить.

От MSDN:

чтения ключевых слов является модификатором, который можно использовать на полях. Когда объявление поля содержит модификатор readonly, присваивания полям, введенным декларацией, могут выполняться только как часть объявления или в конструкторе того же класса.

Это значит, что вам нужно будет удалить ключевое слово readonly, чтобы заставить его работать.

+0

Спасибо, Хаске. К сожалению, вы одобрили мое мнение об этом, я надеялся, что существует какой-то способ решить эту проблему. – 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

Если я правильно помню, это может привести к десериализации для исключения исключения при чтении ввода, который не содержит этого поля. –

Смежные вопросы