序列化可为空类型的正确方法是什么?

发布于 2024-08-02 07:49:21 字数 1522 浏览 6 评论 0 原文

我正在我的一门课程中实现 IXMLSerializable。它包含一些可为 null 的数字属性(int?double?等...)

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

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;
    }
    ...
}

更新: 有人要求我提供一些背景知识来说明为什么要实现 IXmlSerialized。我正在开发一个建筑设计程序,其中我需要一个代表楼层集合的类。每个楼层都有Floor.Area面积、Floor.Height等属性。然而,楼层的标高是由总和定义的其下方的楼层高度。因此,每当Floor.Height属性发生变化或FloorCollection被修改时,楼层的标高都会被重新计算。

我需要序列化的 FloorCollection 类继承自 BindingList。如果我尝试直接序列化此类,它将序列化楼层集合,但不会序列化类中的任何属性或字段。请参阅我的 关于此的上一篇文章

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

现在我认为,总体来说,使用一个单独的布尔值来标识是否存在标高/高度限制,然后使用一个常规的双精度属性来标识限制(如果启用)是什么,可能会更容易。

I'm implementing IXMLSerializable in one of my classes. It contains a few numeric properties that are nullable (int? double? etc..)

What is the correct way to serialize/serialize these through IXMLSerializable? Here's what I'm doing now, which works, but obviously does not seem like the correct way to do it.

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;
    }
    ...
}

Update:
It was asked that I give a little background as to why I am implementing IXmlSerializable. I'm working on a program for architectural design, where I need a class that represents a collection of Floors. Each Floor has properties such as Floor.Area area, Floor.Height etc. The elevation of the floor, however, is defined by the sum of the floor heights below it. So whenever a Floor.Height property changes or the FloorCollection is modified the elevations of the Floors are re-cacluated.

My FloorCollection class, which I need to serialize, inherits from BindingList. If I try to serialize this class directly it will serialize the collection of floors, but not any properties or fields in the class. See my previous post on this.

Now I'm trying to add the ability to restrict the maximum height, maximum top elevation, and minimum bottom elevation of the building floors in the collection. So I'm using nullable doubles to represent these restrictions, where a null value means unrestricted. The elevation properties can be positive, negative, or zero. So there needs to be an alternate state, null, that identifies when there is no restriction.

Now that I think about it might be easier overall to just have a separate Boolean value that identifies if there is a elevation/height restriction, and then a regular double property that identifies what the restriction is if it is enabled.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

画骨成沙 2024-08-09 07:49:21

您希望始终为属性编写 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 命名空间。这将允许您在反序列化期间读回数据类型,以了解是否(以及如何)转换该值。

You want to always write the XML for the property, but if the property value is null you want to include an xsi:nil="true" attribute.

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());
    }
    ...
}

You are also probably going to want to write an xsi:type="xsd:datatype" attribute, where xsd is the http://www.w3.org/2001/XMLSchema namespace. This will allow you to read the data type back in during deserialization to know if (and how) to convert the value.

街道布景 2024-08-09 07:49:21

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

编辑

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

编辑

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

Omit the element if it's null.

edit

Consider what would happen if you made a new version that added a property. If you then deserialized a copy of an old version, the new element containing the new property would be missing, so you would correctly leave the property uninitialized, as null. This is the same logic, extended to cover the present tense.

edit

For information on how to tell XmlSerializer to omit a null property without writing a custom serializer, check out this. Also, given the background information, while I still prefer omission to xsi:nil, I now think the latter is an acceptable solution.

望喜 2024-08-09 07:49:21

您可以编写一个 null:

writer.WriteElementString("Test", null);

它只会产生一个类似 的元素,

或者要更具体地了解 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();
}

这将导致

You can write a null:

writer.WriteElementString("Test", null);

It will just result in an element like <Test/>

Or to be a little more specific about the null value you can use the xsi:nil attribute:

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();
}

which will result in <Test xsi:nil="true"/>

吾性傲以野 2024-08-09 07:49:21
void IXmlSerializable.WriteXml(XmlWriter writer)
{
  if (this._Foo == null)
  {
    writer.WriteStartElement("Foo");
    writer.WriteEndElement("Foo");
  }
  else
  {
    writer.WriteElementString("Foo", this._Foo.ToString());
  }
}
void IXmlSerializable.WriteXml(XmlWriter writer)
{
  if (this._Foo == null)
  {
    writer.WriteStartElement("Foo");
    writer.WriteEndElement("Foo");
  }
  else
  {
    writer.WriteElementString("Foo", this._Foo.ToString());
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文