C#DataContract和序列化readonly bool字段始终为'true'

时间:2017-10-26 19:13:21

标签: c# serialization datacontractserializer

以下课程是一个人为的例子。我希望最简单的方法是每次将'isVisible'字段序列化为'true'时,无论它被设置为什么。

在实际代码中......这是一个更大的对象,并且有一些不同的构造函数可以从不同的点调用。

现在,我可以想到两种方式。

  1. 创建一个'OnSerializing()'方法,该方法使用反射在序列化期间将属性设置为“true”。 (我不确定这是否会起作用......但似乎会这样。)

  2. 在启动类序列化的方法中...在序列化之前创建所有具有isVisible为“true”的新项。

    [DataContract]
    public class MapItem
    {
        public MapItem(bool isVisible)
        {
            this.isVisible = isVisible;
        }
    
        [DataMember]
        private readonly bool isVisible;
    
        public bool IsVisible => isVisible;
    }
    
  3. 为什么我需要这个?基本上,我需要加载这些项目并让它们在加载后始终可见。在运行应用程序时...... MapItems可能变得可见/不可见。因此,我希望XML始终具有<isVisible>true</isVisible>或者我希望MapItem中的值仅在反序列化时为“true”。

1 个答案:

答案 0 :(得分:1)

您希望在反序列化期间将字段private readonly bool isVisible;初始化为true。不幸的是,DataContractSerializer doesn't call any constructor of your class所以没有明显的,简单的方法来做到这一点。

您提出的解决方案 - 在序列化期间始终发出<isVisible>true</isVisible>并利用数据合同序列化程序对只读字段值进行反序列化的能力 - 不太理想,因为它很糟糕精心制作的XML文件,例如<isVisible> false甚至缺失的地方可能会在您的应用中引入意外行为。

相反,请考虑以下不需要序列化isVisible

值的替代方法
  1. 修改只读字段的名称和语义,以使默认值为正确的所需值。在这种情况下,您需要将当前isVisible替换为private readonly bool isNotVisible;

    [DataContract]
    public class MapItem
    {
        // Do not mark with [DataContract] as deserialized instances should always have the default value
        private readonly bool isNotVisible; 
    
        public MapItem(bool isVisible)
        {
            this.isNotVisible = !isVisible;
        }
    
        public bool IsVisible { get { return !isNotVisible; } }
    }
    
  2. 使用反射设置[OnDeserializing]回调中的字段值:

    [DataContract]
    public class MapItem
    {
        public MapItem(bool isVisible)
        {
            this.isVisible = isVisible;
        }
    
        // Do not mark with [DataContract] as deserialized instances should always have the value
        // set in the OnDeserializing() callback.
        private readonly bool isVisible;
    
        public bool IsVisible { get { return isVisible; } }
    
        [OnDeserializing]
        void OnDeserializing(StreamingContext context)
        {
            typeof(MapItem)
                .GetField(nameof(isVisible), BindingFlags.Instance | BindingFlags.NonPublic)
                .SetValue(this, true);
        }
    }
    
  3. 最后,您可以实现ISerializable,因为它是supported by the data contract serializer,并在流式构造函数中初始化isVisibletrue

    [Serializable]
    public class MapItem : ISerializable
    {
        public MapItem(bool isVisible)
        {
            this.isVisible = isVisible;
        }
    
        private readonly bool isVisible;
    
        public bool IsVisible { get { return isVisible; } }
    
        #region ISerializable Members
    
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
        }
    
        #endregion
    
        protected MapItem(SerializationInfo info, StreamingContext context)
        {
            this.isVisible = true;
        }
    }
    

    然而,这是不推荐,因为您现在需要手动序列化所有班级的成员。