C# DataContract 和序列化只读布尔字段始终为 'true'
C# DataContract and Serializing readonly bool field to always be 'true'
下面的class是一个人为的例子。我希望在每次序列化时将 'isVisible' 字段序列化为 'true' 的最简单方法...无论它设置为什么。
在实际代码中...这是一个更大的对象,有几个从不同点调用的不同构造函数。
目前,我想到了两个办法。
创建一个 'OnSerializing()' 方法,在序列化期间使用反射将 属性 设置为 'true'。 (我不确定这是否会起作用……但看起来会起作用)。
在启动 class 序列化的方法中...在序列化之前创建具有 isVisible 的所有新项目作为 'true'。
[DataContract]
public class MapItem
{
public MapItem(bool isVisible)
{
this.isVisible = isVisible;
}
[DataMember]
private readonly bool isVisible;
public bool IsVisible => isVisible;
}
为什么我需要这个?基本上,我需要加载这些项目并让它们在加载后直接可见。虽然 运行 应用程序...MapItems 可能会变成 visible/invisible。因此,我希望 XML 始终具有 <isVisible>true</isVisible>
或者我希望 MapItem 中的值仅在反序列化时为 'true'。
您希望在反序列化期间将字段 private readonly bool isVisible;
初始化为 true
。不幸的是,DataContractSerializer
doesn't call any constructor of your class 所以没有明显、简单的方法来做到这一点。
您提出的解决方案——总是在 序列化 期间发出 <isVisible>true</isVisible>
并利用数据协定序列化程序反序列化只读字段值的能力——较少不理想,因为制作不当的 XML 文件,例如<isVisible>
为 false
甚至缺失的一个,可能会在您的应用程序中引入意外行为。
相反,请考虑以下不需要序列化 isVisible
值的备选方案:
修改只读字段的名称和语义,使默认值为正确的所需值。在这种情况下,您需要将当前的 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; } }
}
使用反射在 [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);
}
}
最后,您可以实现 ISerializable
as this is supported by the data contract serializer,并在流构造函数中将 isVisible
初始化为 true
:
[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;
}
}
但是不推荐,因为您现在需要手动序列化所有 class 的成员。
下面的class是一个人为的例子。我希望在每次序列化时将 'isVisible' 字段序列化为 'true' 的最简单方法...无论它设置为什么。
在实际代码中...这是一个更大的对象,有几个从不同点调用的不同构造函数。
目前,我想到了两个办法。
创建一个 'OnSerializing()' 方法,在序列化期间使用反射将 属性 设置为 'true'。 (我不确定这是否会起作用……但看起来会起作用)。
在启动 class 序列化的方法中...在序列化之前创建具有 isVisible 的所有新项目作为 'true'。
[DataContract] public class MapItem { public MapItem(bool isVisible) { this.isVisible = isVisible; } [DataMember] private readonly bool isVisible; public bool IsVisible => isVisible; }
为什么我需要这个?基本上,我需要加载这些项目并让它们在加载后直接可见。虽然 运行 应用程序...MapItems 可能会变成 visible/invisible。因此,我希望 XML 始终具有 <isVisible>true</isVisible>
或者我希望 MapItem 中的值仅在反序列化时为 'true'。
您希望在反序列化期间将字段 private readonly bool isVisible;
初始化为 true
。不幸的是,DataContractSerializer
doesn't call any constructor of your class 所以没有明显、简单的方法来做到这一点。
您提出的解决方案——总是在 序列化 期间发出 <isVisible>true</isVisible>
并利用数据协定序列化程序反序列化只读字段值的能力——较少不理想,因为制作不当的 XML 文件,例如<isVisible>
为 false
甚至缺失的一个,可能会在您的应用程序中引入意外行为。
相反,请考虑以下不需要序列化 isVisible
值的备选方案:
修改只读字段的名称和语义,使默认值为正确的所需值。在这种情况下,您需要将当前的
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; } } }
使用反射在
[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); } }
最后,您可以实现
ISerializable
as this is supported by the data contract serializer,并在流构造函数中将isVisible
初始化为true
:[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; } }
但是不推荐,因为您现在需要手动序列化所有 class 的成员。