C#Xml序列化程序将列表反序列化为计数为0而不是null
我对幕后的工作方式感到困惑。我有一个将XML反序列化为对象的类。我看到的是以下两个元素,它们不是反序列化Xml的一部分C#Xml序列化程序将列表反序列化为计数为0而不是null,c#,xml,serialization,xmlserializer,C#,Xml,Serialization,Xmlserializer,我对幕后的工作方式感到困惑。我有一个将XML反序列化为对象的类。我看到的是以下两个元素,它们不是反序列化Xml的一部分 [XmlRootAttribute("MyClass", Namespace = "", IsNullable = false)] public class MyClass { private string comments; public string Comments { set { comments = value; }
[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; }
}
}
[XmlRootAttribute(“MyClass”,Namespace=”“,IsNullable=false)]
公共类MyClass
{
私有字符串注释;
公共字符串注释
{
设置{comments=value;}
获取{返回注释;}
}
private System.Collections.Generic.List tests=null;
公共系统.Collections.Generic.List测试
{
获取{返回测试;}
设置{tests=value;}
}
}
让我们以以下XML为例:
<MyClass>
<SomeNode>value</SomeNode>
</MyClass>
价值
您注意到测试和注释不是XML的一部分
当这个XML被反序列化时,注释为null(这是应该的),Tests是一个计数为0的空列表
如果有人能向我解释这一点,我将不胜感激。我更喜欢的是,如果XML中缺少
,那么列表应该保持为空,但是如果节点
存在,则应分配列表。您观察到的是,在反序列化开始时,XmlSerializer
会自动预分配引用可修改集合(如list
)的成员。我不知道有任何地方记录了这种行为。它可能与到中描述的行为有关,该行为说明,由于XmlSerializer
,如果预分配的集合包含默认项,则反序列化的项将附加到该集合中-可能会复制内容。微软可能只是选择在反序列化开始时预先分配所有可修改的集合,作为实现这一点的最简单方法
这个答案的解决方法,即使用代理数组属性,也适用于这里。由于数组不能追加到,因此,XmlSerializer
必须累加所有值,并在反序列化完成时将其设置回原位。但是如果从未遇到相关标记,XmlSerializer
显然不会开始累积值,因此不会调用数组setter。这似乎可以防止默认预分配您不想要的集合:
[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);
}
}
}
[XmlRootAttribute(“MyClass”,Namespace=”“,IsNullable=false)]
公共类MyClass
{
私有字符串注释;
公共字符串注释
{
设置{comments=value;}
获取{返回注释;}
}
private System.Collections.Generic.List tests=null;
[XmlIgnore]
公共系统.Collections.Generic.List测试
{
获取{返回测试;}
设置{tests=value;}
}
[XmlArray(“测试”)]
公共字符串[]TestsArray
{
得到
{
返回(Tests==null?null:Tests.ToArray());
}
设置
{
如果(值==null)
返回;
(测试=测试??新列表(值.长度)).AddRange(值);
}
}
}
示例显示,
测试
仅在适当时分配。在谷歌搜索相同问题后,我们在此结束。
我们最终做的是在反序列化之后检查Count==0,并手动将属性设置为null
...
var varMyDeserializedClass = MyXmlSerializer.Deserialize(new StringReader(myInput));
if (varMyDeserializedClass.ListProperty.Count == 0)
{
varMyDeserializedClass.ListProperty = null;
}
...
这是一种廉价的解决方法,但提供了预期的结果,有助于避免重构或重新设计。当您将
[System.Xml.Serialization.xmlement(IsNullable=true)]
应用于属性时,反序列化后列表将为空。另一种可能是使用“magic”“Specified”后缀:
如果指定了序列化字段/属性XXX和布尔属性XXX,然后根据是否设置了主字段/属性来设置bool属性。@gdir您是说当您序列化此字段/属性时,列表的值将为null而不是空列表?不,我想问的是,因为测试不是xml的一部分,所以序列化时,它应该为null而不是空列表。这有意义吗?OP的问题是关于反序列化而不是序列化。当对上面的XML进行反序列化时,将分配
测试集合,即使
从未出现在XML中。(顺便说一句,我可以复制它。)编辑为反序列化,我不知道这种行为记录在什么地方。当
完全丢失时,您不希望分配列表。当存在空的
节点时,您想要什么?
public bool TestsSpecified {get;set;}