Инициализировать частные поля только для чтения после десериализации - PullRequest
12 голосов
/ 17 февраля 2012

Мне нужно инициализировать приватное поле только для чтения после десериализации. У меня есть следующий 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 не было нулевым.

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

Ответы [ 2 ]

10 голосов
/ 13 сентября 2012

Сериализация может считывать значения для полей только для чтения, поскольку использует отражение, которое игнорирует правила доступности.Можно утверждать, что следующее является оправданным как часть процесса сериализации, хотя я настоятельно рекомендовал бы против него практически при любых других обстоятельствах:

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));
    }
}
7 голосов
/ 17 февраля 2012

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

С MSDN :

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

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

...