Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialize private readonly fields after Deserializing

I need to initialize private readonly field after Deserialization. I have folowing 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();
    }
}

All what I need, that after Deserialization _privateReadonlyField is not null.

Any suggestions about this - is it possible at all? Or I need to remove "readonly" key, which is not a good option.

like image 857
Andris Avatar asked Feb 17 '12 13:02

Andris


Video Answer


2 Answers

Serialization is able to read in values for read-only fields because it uses reflection, which ignores accessibility rules. It can be argued that the following is, therefore, justified as part of the serialization process, even though I would recommend strongly against it in almost any other circumstance:

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));
    }
}
like image 96
Tim Sylvester Avatar answered Oct 04 '22 06:10

Tim Sylvester


Any field declared as private readonly can be instantiated in the same line where it was declared or inside a constructor. Once that is done it cannot be changed.

From MSDN:

The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.

That means that you will have to remove readonly keyword to get it to work.

like image 44
Husein Roncevic Avatar answered Oct 04 '22 05:10

Husein Roncevic