我有一个通过C#,.NET 3.5中的XmlSerializer进行序列化/反序列化的对象。其中一个属性(以及将来的更多属性)是一个集合:List其中T是枚举值。这序列化/反序列化很好。
我们还使用“默认值”机制为对象提供默认值,以防序列化版本没有设置任何值。举一个简单的例子,这就是我们的目标:
public enum MyEnum {
Value1,
Value2
}
public class Foo
{
public List SomeSetting{ get; set; }
public Foo()
{
SomeSetting = new List();
SomeSetting.Add(MyEnum.Value1);
SomeSetting.Add(MyEnum.Value2);
}
}
此代码适用于在构造对象时设置SomeSetting的默认值。
但是,当我们反序列化具有SomeSetting值的xml文件时,此默认值设置会导致问题:xml反序列化器不会“重置”SomeSetting集合 - 它不会擦除它并用新数据填充。相反,它增加了已经存在的数据。因此,如果xml文件将Value1序列化到其中,当我反序列化该文件时,我最终会将SomeSettings {Value1,Value2,Value1}作为存储的值。
我需要一种方法来使xml反序列化过程允许在xml文档中没有SomeSetting的数据时存在我的默认值,并且当xml文档中有数据时批量替换SomeSetting值。我怎么能这样做?
仅供参考 - 这不是文件中唯一的财产。该文档确实存在,并且正在针对其他“简单”值进行序列化/反序列化。但是,这是导致问题的属性。我必须支持这种情况,因为我现在需要做很多事情。
答案 0 :(得分:1)
仅供参考 - 我使用IXMLSerializable接口解决了这个问题。请注意,此代码非常特定于我在这一类中的需求,因此YMMV。
public void WriteXml(XmlWriter writer)
{
foreach (PropertyInfo prop in GetType().GetProperties())
{
XmlIgnoreAttribute attr;
if (prop.TryGetAttribute(out attr))
continue;
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition().Equals(typeof(List)))
{
XmlSerializer serializer = new XmlSerializer(prop.PropertyType, new XmlRootAttribute(prop.Name));
serializer.Serialize(writer, prop.GetValue(this, null));
}
else
{
writer.WriteElementString(prop.Name, prop.GetValue(this, null).ToString());
}
}
}
public void ReadXml(XmlReader reader)
{
if (reader.IsEmptyElement)
return;
XmlDocument xDoc = new XmlDocument();
xDoc.Load(reader);
Type type = GetType();
foreach (XmlNode node in xDoc.DocumentElement.ChildNodes)
{
PropertyInfo prop = type.GetProperty(node.Name);
if (prop != null && prop.CanWrite)
{
object value;
if (prop.PropertyType.IsEnum)
{
string stringValue = node.InnerText;
value = Enum.Parse(prop.PropertyType, stringValue);
}
else if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition().Equals(typeof(List)))
{
Type enumType = prop.PropertyType.GetGenericArguments()[0];
value = Activator.CreateInstance(prop.PropertyType);
var addMethod = value.GetType().GetMethod("Add");
foreach (XmlNode subNode in node.ChildNodes)
{
object enumValue = Enum.Parse(enumType, subNode.InnerText);
addMethod.Invoke(value, new[] { enumValue });
}
}
else
{
string stringValue = node.InnerText;
value = Convert.ChangeType(stringValue, prop.PropertyType);
}
prop.SetValue(this, value, null);
}
}
}
public XmlSchema GetSchema()
{
return null;
}
答案 1 :(得分:0)
快速而肮脏的是实施ISupportInitialize。所有.NET序列化程序(IIRC)都遵循此接口,并在反序列化后调用EndInit
。
此时您可以检查集合的内容,并确定是否应该添加默认值。我还建议检查你的实例是否在第一次使用之前已经初始化,如果没有,则抛出异常。这将确保您班级的其他用户知道您的实例必须在使用前初始化。
答案 2 :(得分:0)
另一种选择,而不是自己解析XML,我们可以使用我使用的方法。只是一个建议。