如何在c#中将null数组反序列化为null?

时间:2010-03-30 09:56:28

标签: c# xml arrays serialization nullable

这是我的班级:

public class Command
{
   [XmlArray(IsNullable = true)]
   public List<Parameter> To { get; set; }
}

当我序列化这个类的对象时:

var s = new XmlSerializer(typeof(Command));
s.Serialize(Console.Out, new Command());

按预期打印(省略xml标头和默认MS名称空间):

<Command><To xsi:nil="true" /></Command>

当我拿这个xml并试图反序列化时,我被卡住了,因为它总是打印“Not null”:

var t = s.Deserialize(...);
if (t.To == null)
    Console.WriteLine("Null");
else
    Console.WriteLine("Not null");

如果强制反序列化器使我的列表为空,如果它在xml中为null?

5 个答案:

答案 0 :(得分:3)

如果使用数组而不是列表,则按预期工作

public class Command
{
    [XmlArray(IsNullable = true)]
    public Parameter[] To { get; set; }
}

答案 1 :(得分:2)

嗯,烦人不是吗。您可以通过使用/ keep和/ debug选项在程序集上运行sgen.exe来查看它正在执行的操作,以便您可以调试反序列化代码。看起来大致如下:

global::Command o;
o = new global::Command();
if ((object)(o.@To) == null) o.@To = new global::System.Collections.Generic.List<global::Parameter>();
global::System.Collections.Generic.List<global::Parameter> a_0 = (global::System.Collections.Generic.List<global::Parameter>)o.@To;
// code elided
//...
while (Reader.NodeType != System.Xml.XmlNodeType.EndElement && Reader.NodeType != System.Xml.XmlNodeType.None) {
  if (Reader.NodeType == System.Xml.XmlNodeType.Element) {
    if (((object)Reader.LocalName == (object)id4_To && (object)Reader.NamespaceURI == (object)id2_Item)) {
      if (!ReadNull()) {
        if ((object)(o.@To) == null) o.@To = new global::System.Collections.Generic.List<global::Parameter>();
        global::System.Collections.Generic.List<global::Parameter> a_0_0 = (global::System.Collections.Generic.List<global::Parameter>)o.@To;
        // code elided
        //...
      }
      else {
        // Problem here:
        if ((object)(o.@To) == null) o.@To = new global::System.Collections.Generic.List<global::Parameter>();
        global::System.Collections.Generic.List<global::Parameter> a_0_0 = (global::System.Collections.Generic.List<global::Parameter>)o.@To;
      }
    }
  }
  Reader.MoveToContent();
  CheckReaderCount(ref whileIterations1, ref readerCount1);
}
ReadEndElement();
return o;

不少于3个地方确保@To属性不为null。第一个是有点可辩护的,当结构不存在时难以反序列化数据。第二个再次进行空测试 ,这是唯一真正好的测试。第三个是问题,ReadNull()返回true但仍然创建一个非null属性值。

如果你想区分空和null,那么你没有好的解决方案,但手动编辑这段代码。如果你真的很绝望并且该课程100%稳定,那么这只 。好吧,不要这样做。 João的解决方案是唯一的好解决方案。

答案 2 :(得分:0)

我同意@Oliver的评论,但是你可以像这样解决它,如果你绝对需要它来返回null。而不是使用自动属性,创建自己的支持字段。

List<Parameter> _to;
public List<Parameter> To
{
    get
    {
        if (_to != null && _to.Count == 0) return null;
        return _to;
    }
    set { _to = value; }
}

答案 3 :(得分:0)

如果你确实需要将一个集合反序列化为null,当没有提供任何值时,你可以通过不提供set访问器来实现,如下所示:

public class Command
{
    private List<Parameter> to;

    public List<Parameter> To { get { return this.to; } }
}

答案 4 :(得分:0)

对于需要它的人,可以将其类型定义为具有原始元素名称的数组,然后将其包装,这将为您提供可为空的列表。

[XmlArray(ElementName = nameof(Metadata), IsNullable = true)]
public string[] MetadataArray { get; set; }

[XmlIgnore]
public List<string> Metadata
{
    get => this.MetadataArray?.ToList();
    set => this.MetadataArray = value?.ToArray();
}