反序列化后初始化私有只读字段

时间:2012-02-17 13:03:28

标签: c# initialization private deserialization readonly

我需要在反序列化后初始化私有只读字段。我有以下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”键,这不是一个好的选择。

2 个答案:

答案 0 :(得分:10)

序列化能够读取只读字段的值,因为它使用反射,忽略了可访问性规则。可以说,以下是作为序列化过程的一部分是合理的,尽管我会在几乎任何其他情况下强烈反对它:

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 :(得分:7)

声明为private readonly的任何字段都可以在声明它的同一行或构造函数中实例化。一旦完成,就无法更改。

来自MSDN

  

readonly关键字是一个可以在字段上使用的修饰符。当字段声明包含只读修饰符时,声明引入的字段的赋值只能作为声明的一部分或在同一类的构造函数中出现。

这意味着您必须删除readonly关键字才能使其生效。