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


我需要在反序列化后初始化私有只读字段。我有以下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不为null。

对此有任何建议 - 是否有可能? 或者我需要删除“readonly”键,这不是一个好的选择。


3068
2018-02-17 13:03


起源

你使用什么序列化方法?对象的构造因不同方法而不同。 - Joachim Isaksson
标记你的错误有什么问题 _privateReadonlyField 一个 [DataMember]?数据合同序列化器会毫无问题地处理它。 - dasblinkenlight
Joachim Isaksson:我正在使用DataContractJsonSerializer,但实际上这并不重要 - 所有序列化程序在反序列化时都使用FormatterServices.GetUninitializedObject。 - Andris
dasblinkenlight:我不需要序列化字段的值。当我的Item被反序列化时,我只需要让这个字段不为null。 - Andris


答案:


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

MSDN

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

这意味着你必须删除 readonly 让它运作的关键字。


7
2018-02-17 13:06



谢谢,胡斯克。不幸的是你批准了我对此的感觉,我希望有一些方法来解决这个问题。 - Andris


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

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));
    }
}

8
2017-09-13 02:36



谢谢你的回复。当被问到这个问题时,我真的忘记了反思。 - Andris
有什么影响呢 [OptionalField] 属性有这个解决方案吗?是否 OnDeserialized 没有它仍然工作? - Tim Long
如果我没记错的话,省略它将导致反序列化在读取不包含该字段的输入时抛出异常。 - Tim Sylvester