C#Xml序列化器将列表反序列化为0而不是null

Max*_*eue 5 c# xml serialization xmlserializer

XmlSerializer对幕后工作方式感到困惑。我有一个将XML反序列化为对象的类。我看到的是以下两个元素,它们不是正在反序列化的Xml的一部分。

[XmlRootAttribute("MyClass", Namespace = "", IsNullable = false)]
public class MyClass
{
    private string comments;
    public string Comments
    {
        set { comments = value; }
        get { return comments; }
    }

    private System.Collections.Generic.List<string> tests = null;
    public System.Collections.Generic.List<string> Tests
    {
        get { return tests; }
        set { tests = value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

让我们以以下XML为例:

<MyClass>
  <SomeNode>value</SomeNode>
</MyClass>
Run Code Online (Sandbox Code Playgroud)

您会注意到测试和注释不是XML的一部分。

对该XML进行反序列化时,Comment为null(这是预期的),而Tests是一个空列表,计数为0。

如果有人可以向我解释这一点,将不胜感激。我更希望的是,如果<Tests>XML中缺少该列表,则该列表应保持为空,但是如果存在(可能为空)节点<Tests />,则应分配该列表。

dbc*_*dbc 5

您观察到的是,引用可修改集合的成员,例如在反序列化开始时List<T>自动预先分配的成员。XmlSerializer我不知道有任何地方记录了这种行为。它可能与此答案中描述的行为有关XML Deserialization of collection property with code defaults,这解释了,由于XmlSerializer 支持添加到仅获取和预分配的集合,如果预分配的集合包含默认项目,则反序列化的集合项目将被附加到它 - 可能会重复内容。Microsoft 可能只是选择在反序列化开始时预先分配所有可修改的集合,作为实现此目的的最简单方法。

该答案的解决方法,即使用代理数组属性,在这里也适用。由于无法追加数组,因此XmlSerializer必须累积所有值并在反序列化完成时将它们设置回原位。但是,如果从未遇到相关标签,则XmlSerializer显然不会开始累积值,因此不会调用数组设置器。这似乎可以防止默认预分配您不想要的集合:

[XmlRootAttribute("MyClass", Namespace = "", IsNullable = false)]
public class MyClass
{
    private string comments;
    public string Comments
    {
        set { comments = value; }
        get { return comments; }
    }

    private System.Collections.Generic.List<string> tests = null;

    [XmlIgnore]
    public System.Collections.Generic.List<string> Tests
    {
        get { return tests; }
        set { tests = value; }
    }

    [XmlArray("Tests")]
    public string[] TestsArray
    {
        get
        {
            return (Tests == null ? null : Tests.ToArray());
        }
        set
        {
            if (value == null)
                return;
            (Tests = Tests ?? new List<string>(value.Length)).AddRange(value);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

示例.Net fiddle显示Tests仅在适当时分配。