XmlSerializer和List 具有默认值

我在序列化时观察到一种奇怪的行为,而不是反序列化具有List类型成员的类,该类在构造时填充了默认值。 与基于数组的属性不同, List类型的属性在XmlSerializer的反序列化时不会被清空。

这是我的代码:

 public class Program { public class Config { public Config() { Test1 = new List() {"A", "B"}; Test2 = new String[] {"A", "B"}; } public List Test1 {get;set;} public string[] Test2 {get;set;} } public static void Main() { XmlSerializer xmlSerializer = new XmlSerializer(typeof(Config)); using(Stream s = new MemoryStream()) { xmlSerializer.Serialize(s, new Config()); s.Position = 0; xmlSerializer.Serialize(Console.Out, xmlSerializer.Deserialize(s)); } } } 

这是输出:

    A B A B   A B   

为什么List由XmlSerializer以不同于数组的方式处理,我该怎么做才能改变这种行为?

有趣; 我以前从未注意到它,但它绝对可以重现。 由于XmlSerializer不支持序列化回调(以帮助您知道它正在运行以进行序列化),因此很难影响; 可以说最简单的答案是“不要将默认数据放入构造函数中的对象”(尽管可能提供一种工厂方法)。

可以尝试实现IXmlSerializable ,但即使是一个简单的示例,这也很难做到。

我已经检查过,并且DataContractSerializer 会这样做 – 所以你可以切换到DataContractSerializer ; 这是我的DCS测试代码:

 DataContractSerializer ser = new DataContractSerializer(typeof(Config)); using (Stream s = new MemoryStream()) { ser.WriteObject(s, new Config()); s.Position = 0; using(var writer = XmlWriter.Create(Console.Out)) { ser.WriteObject(writer, ser.ReadObject(s)); } } 

这就是我所说的工厂方法:

 public class Config { public Config() { Test1 = new List(); Test2 = nix; } public List Test1 { get; set; } public string[] Test2 { get; set; } private static readonly string[] nix = new string[0]; public static Config CreateDefault() { Config config = new Config(); config.Test1.Add("A"); config.Test1.Add("B"); config.Test2 = new string[2] { "A", "B" }; return config; } } 

当列表包含在构造函数中创建的一组默认条目时,这确实是令人沮丧的XML反序列化行为。

我的解决方法是在List上设置XMLIgnoreAttribute并包含对象类型的数组的公共成员,其中set / get处理数组中列表的填充。

类似下面的内容允许在构造函数中创建默认值,但保持XML序列化程序不将条目添加到默认列表。 (错误/无效validation)。

 public class Config { public Config() { Test1 = new List() { "A", "B" }; Test2 = new String[] { "A", "B" }; } [XmlIgnore] public List Test1 { get; set; } public string[] Test2 { get; set; } // This member is only to be used during XML serialization public string[] Test1_Array { get { return Test1.ToArray(); } set { Test1 = value.ToList(); } } }