Blog of me, Chris Idzerda, containing my thoughts, comments, and questions. RSS Feed


The nil attribute in XML-serialized nullable values

If in a class you have a value type property that is optional, it's common to specify it as nullable. However, if you serialize a nullable value type property to XML, you'll get something like this if it's null.

<Value xsi:nil="true" />

Or, if you turned off declaration of the XML schema instance namespace, it will be even more verbose.

<Value p2:nil="true" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance" />

This might look strange but it will properly deserialize. Nonetheless, you might have a reason to have a nullable value type property serialize the way a class property does, which is to not appear in the XML output at all if it's null. Setting the IsNullable property of the XmlElement attribute for such a property will have no effect. (Well, setting it to false will result in a run-time error.)

The XmlElementAttribute.IsNullable Property page at MSDN has this to say.

You cannot apply the IsNullable property to a member typed as a value type because a value type cannot contain null. Additionally, you cannot set this property to false for nullable value types. When such types are null, they will be serialized by setting xsi:nil to true.

One work-around is to declare another property that is a class type, such as string, and parse it in the nullable value property.

[XmlElement("Value")]
public string ValueString { get; set; }

[XmlIgnore]
public int? Value
{
    get { return int.Parse(ValueString); }
    set { ValueString= value.ToString(); }
}

Of course, you can go in the opposite direction as well.

[XmlElement("Value")]
public string ValueString
{
    get { return Value.HasValue ? Value.Value.ToString() : null; }
    set
    {
        if(value != null)
            Value= int.Parse(value);
        else
            Value= null;
    }
}

[XmlIgnore]
public int? Value { get; set; }

 
Posted by Chris Idzerda | 2 Comments | Trackback Url | Bookmark with:        
Tags:

Links to this Post

Comments

Thursday, 29 May 2008 05:54 by Alternative Approach
Chris: An alternative to wrapping the integer value in a string is to use another public member that has the exact same name as the original member, but with "Specified" appended: [XmlElement("Value")] public int MyValue { get; set; } [XmlIgnore] public bool MyValueSpecified { get; set; } The MyValueSpecified member has to be a boolean type. If you set this to False, MyValue will not be serialized. Setting MyValueSpecified to True will force MyValue to be serialized. Check out http://bytes.com/forum/thread176928.html for another example. This trick with the "...Specified" will work with a member of any data type - integers, dates, booleans, strings, custom classes, etc.. I don't think I've tried it with an enumeration, but I would suspect it would work there as well. I'm not entirely happy that the fields are linked purely based on their names, and this fact has caused me a little grief already (a situation where I really wanted a separate member called BlahSpecified), but on the code-smell scale it's not bad, especially if you encapsulate this serialize/don't serialize logic in your class constructor. Mark. www.mark-gilbert.com

Wednesday, 4 Jun 2008 07:18 by RE: Alternative Approach
Mark, I had all but forgotten the "Specified" mechanism until your comment reminded me of it. It's nice that it works with any type but I agree it's a bit unsettling that it is based on a convention. Also, it requires setting two properties to get the desired output whereas a nullable type with an adjunct serializing property doesn't. Chris

Name:
URL:
Email:
Comments:

CAPTCHA Image Validation