C#XML反序列化W /默认值

时间:2009-12-28 15:09:23

标签: xml-serialization default-value xml-deserialization

我有一个通过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值。我怎么能这样做?

仅供参考 - 这不是文件中唯一的财产。该文档确实存在,并且正在针对其他“简单”值进行序列化/反序列化。但是,这是导致问题的属性。我必须支持这种情况,因为我现在需要做很多事情。

3 个答案:

答案 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,我们可以使用我使用的方法。只是一个建议。

C# Xml Deserialize plus design suggestions