如何使用.NET XmlSerializer使值类型为空?

时间:2009-03-31 21:30:18

标签: c# xml-serialization null value-type

假设我有这个对象:

[Serializable]
public class MyClass
{
    public int Age { get; set; }
    public int MyClassB { get; set; }
}
[Serializable]
public class MyClassB
{
    public int RandomNumber { get; set; }
}

XmlSerializer会像这样序列化对象:

<MyClass>
    <Age>0</age>
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>

我怎样才能使该物业成为可空? IE:当它低于0时,不将序列化属性Age?

我尝试使用Nullable,但它会像我那样序列化我的对象:

<MyClass>
    <Age d5p1:nil="true" />
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>    

通过阅读MSDN文档,我发现了这个:

  

您不能将IsNullable属性应用于键入为值类型的成员,因为值类型不能包含nullNothingnullptra null引用(在Visual Basic中为Nothing)。此外,对于可空值类型,您不能将此属性设置为false。当这些类型为nullNothingnullptra null引用(在Visual Basic中为Nothing)时,它们将通过将xsi:nil设置为true来序列化。

来源:http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlelementattribute.isnullable.aspx

我理解值类型不能设置为null。值类型始终设置为某种值。序列化不能根据它的当前值决定是否序列化它。

我尝试了这些属性,但它没有成功。我尝试创建一个agecontainer对象并使用属性操作它的序列化,但它没有用完。

我真正想要的是:

<MyClass>
    <MyClassB>
        <RandomNumber>4234</RandomNumber>
    </MyClassB>
</MyClass>

当物业年龄低于0(零)时。


  

看起来你必须实现自定义序列化。

是的,那也是我的意思,但我想在没有它的情况下离开。

在应用程序中,对象要复杂得多,我不想自己处理序列化。

6 个答案:

答案 0 :(得分:53)

我刚发现了这个。 XmlSerialier查找XXXSpecified布尔属性以确定是否应包含它。这应该可以很好地解决问题。

[Serializable]
public class MyClass
{
  public int Age { get; set; }
  [XmlIgnore]
  public bool AgeSpecified { get { return Age >= 0; } }
  public int MyClassB { get; set; }
}

[Serializable]
public class MyClassB
{
  public int RandomNumber { get; set; }
}

证明:

static string Serialize<T>(T obj)
{
  var serializer = new XmlSerializer(typeof(T));
  var builder = new StringBuilder();
  using (var writer = new StringWriter(builder))
  {
    serializer.Serialize(writer, obj);
    return builder.ToString();
  }
}

static void Main(string[] args)
{
  var withoutAge = new MyClass() { Age = -1 };
  var withAge = new MyClass() { Age = 20 };

  Serialize(withoutAge); // = <MyClass><MyClassB>0</MyClassB></MyClass>
  Serialize(withAge); // = <MyClass><Age>20</Age><MyClassB>0</MyClassB></MyClass>
}

修改:是的,这是一个记录在案的功能。请参阅MSDN entry for XmlSerializer

  

另一种选择是使用特殊模式创建XmlSerializer可识别的布尔字段,并将XmlIgnoreAttribute应用于该字段。该模式以propertyNameSpecified的形式创建。例如,如果有一个名为“MyFirstName”的字段,您还将创建一个名为“MyFirstNameSpecified”的字段,该字段指示XmlSerializer是否生成名为“MyFirstName”的XML元素。

答案 1 :(得分:13)

将Samuel的答案和Greg Beech的评论扩展到布尔属性的情况:如果属性是bool类型,那么你就不能在propertySpecified属性中编写一个简单的测试。

解决方案是使用Nullable&lt; bool&gt;类型,那么propertySpecified属性中的测试就是property.HasValue。 e.g。

using System.Xml.Serialization;

public class Person
{
    public bool? Employed { get; set; }

    [XmlIgnore]
    public bool EmployedSpecified { get { return Employed.HasValue; } }
}

对数字属性使用可空类型(由Greg Beech建议)的替代方法是将value属性设置为无效的默认值,例如-1,如下所示:

using System.ComponentModel;
using System.Xml.Serialization;

public class Person
{
    [DefaultValue(-1)]
    public int Age { get; set; }

    [XmlIgnore]
    public bool AgeSpecified { get { return Age >= 0; } }
}

答案 2 :(得分:4)

您可以使用 XmlElementAttribute.IsNullable

[Serializable]
public class MyClass
{
    [XmlElement(IsNullable = true)]
    public int? Age { get; set; }

    public int MyClassB { get; set; }
}

答案 3 :(得分:2)

这应该有所帮助 Make Age int?和..

public bool ShouldSerializeAge() { return Age.HasValue; }

..这意味着将ShouldSerializeXXX方法添加到您的班级!

答案 4 :(得分:0)

忘记Nullable ...... ShouldSerializeXXX是一个非常好的解决方案。 这里的年龄将根据您的情况系列化。

[Serializable]
public class MyClass
{
    public int Age { get; set; }
    public int MyClassB { get; set; }

    #region Conditional Serialization
    public bool ShouldSerializeAge() { return age > 0; }
    #endregion
}

[Serializable]
public class MyClassB
{
    public int RandomNumber { get; set; }
}

答案 5 :(得分:0)

如果您将'minoccurs'属性设置为'minoccurs =“0”',则xsd.exe将自动生成XXXSpecified属性和访问器...如果您使用模式来定义xml / class