Инициализировать приватные поля readonly после Deserializing
Мне нужно инициализировать личное поле readonly после Deserialization. У меня есть DataContract:
[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", что не является хорошим вариантом.
Ответы
Ответ 1
Любое поле, объявленное как private readonly
, может быть создано в той же строке, где оно было объявлено или внутри конструктора. Как только это будет сделано, он не может быть изменен.
От MSDN:
Ключевое слово readonly - это модификатор, который можно использовать для полей. Когда объявление поля включает модификатор readonly, присваивания полям, введенным декларацией, могут возникать только как часть объявления или в конструкторе того же класса.
Это означает, что вам нужно удалить ключевое слово readonly
, чтобы заставить его работать.
Ответ 2
Сериализация может считывать значения для полей только для чтения, поскольку использует отражение, которое игнорирует правила доступности. Можно утверждать, что, следовательно, оправдано следующее в процессе сериализации, хотя я бы настоятельно рекомендовал его практически в любых других обстоятельствах:
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));
}
}