2

我有一个对象正在通过 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 值。我怎样才能做到这一点?

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

4

3 回答 3

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;
        }
于 2009-12-30T17:14:15.830 回答
0

快速而肮脏的是实现ISupportInitialize。所有 .NET 序列化程序 (IIRC) 都尊重此接口,并将EndInit在反序列化后调用。

此时您可以检查集合的内容,并确定是否应该在那时添加默认值。我还建议在首次使用之前检查您的实例是否已初始化,如果尚未初始化则抛出异常。这将确保您班级的其他用户知道您的实例必须在使用前进行初始化。

于 2009-12-28T15:14:36.953 回答
0

除了自己解析 XML 之外,还有另一种选择,我们可以使用我使用的方法。只是一个建议。

C# Xml反序列化加设计建议

于 2013-02-08T19:32:29.943 回答