1

我正在我的一个类中实现 IXMLSerializable。它包含一些可以为空的数字属性(int?double?等)

通过 IXMLSerializable 序列化/序列化这些的正确方法是什么?这就是我现在正在做的事情,它有效,但显然似乎不是正确的方法。

void IXmlSerializable.WriteXml(XmlWriter writer)
{
    ...

    if (this._PropName == null)
    {
        writer.WriteElementString("PropName", "NULL");
    }
    else
    {
        writer.WriteElementString("PropName", this._PropName.ToString());
    }
    ...
}

void IXmlSerializable.ReadXml(XmlReader reader)    
{
    string tempStr;
    ...

    reader.ReadStartElement("PropName"); 

    if (tempStr != "NULL")
    {
        this._PropName = double.Parse(tempStr);
    }
    else 
    {
        this._PropName = null;
    }
    ...
}

更新: 有人问我为什么要实现IXmlSerializable的背景知识。我正在开发一个建筑设计程序,我需要一个代表楼层集合的类。每个楼层都具有诸如Floor.Area面积、Floor.Height等属性。但是,楼层的标高由其下方楼层高度的总和定义。因此,每当Floor.Height属性更改或FloorCollection被修改时,都会重新计算Floors的高度。

我需要序列化的FloorCollection类继承自 BindingList。如果我尝试直接序列化此类,它将序列化楼层的集合,但不会序列化类中的任何属性或字段。请参阅我之前的帖子

现在我正在尝试添加限制集合中建筑物楼层的最大高度、最大顶部标高和最小底部标高的功能。所以我使用可为空的双精度来表示这些限制,其中空值表示不受限制。高程属性可以是正数、负数或零。因此,需要有一个备用状态 null 来标识何时没有限制。

现在我想,如果有一个单独的布尔值来标识是否存在海拔/高度限制,然后有一个常规的双属性来标识启用它的限制是什么,总体上可能会更容易。

4

4 回答 4

3

如果元素为空,则省略该元素。

编辑

考虑一下如果您制作了一个添加属性的新版本会发生什么。如果您随后反序列化旧版本的副本,则包含新属性的新元素将丢失,因此您可以正确地将属性保留为未初始化,为 null。这是相同的逻辑,扩展到涵盖现在时。

编辑

有关如何告诉 XmlSerializer 在不编写自定义序列化程序的情况下省略 null 属性的信息,请查看。此外,鉴于背景信息,虽然我仍然更喜欢省略 xsi:nil,但我现在认为后者是一个可以接受的解决方案。

于 2009-08-18T02:22:38.927 回答
3

您希望始终为属性编写 XML,但如果属性值为 null,您希望包含 xsi:nil="true" 属性。

void IXmlSerializable.WriteXml(XmlWriter writer)
{
    ...

    if (this._PropName == null)
    {
        writer.WriteStartElement("PropName");
        writer.WriteAttributeString("xsi", "nil", "http://www.w3.org/2001/XMLSchema-instance", "true");
        writer.WriteEndElement();
    }
    else
    {
        writer.WriteElementString("PropName", this._PropName.ToString());
    }
    ...
}

您可能还想编写一个 xsi:type="xsd: datatype " 属性,其中 xsd 是http://www.w3.org/2001/XMLSchema命名空间。这将允许您在反序列化期间重新读取数据类型,以了解是否(以及如何)转换该值。

于 2009-08-18T02:46:39.670 回答
1

你可以写一个空:

writer.WriteElementString("Test", null);

它只会产生一个像<Test/>

或者更具体地了解 null 值,您可以使用xsi:nil属性:

const string xsiNs = "http://www.w3.org/2001/XMLSchema-instance";
using (XmlWriter writer = XmlWriter.Create(Console.Out))
{
  writer.WriteStartElement("Test");
  writer.WriteAttributeString("xsi", "nil", xsiNs, "true");
  writer.WriteEndElement();
}

这将导致<Test xsi:nil="true"/>

于 2009-08-18T02:38:14.583 回答
0
void IXmlSerializable.WriteXml(XmlWriter writer)
{
  if (this._Foo == null)
  {
    writer.WriteStartElement("Foo");
    writer.WriteEndElement("Foo");
  }
  else
  {
    writer.WriteElementString("Foo", this._Foo.ToString());
  }
}
于 2009-08-18T02:28:31.057 回答