0

This is a note to my future self, and for the benefit of others. The described behavoir is NOT obvious...

I've got this bit of C#:

public enum Choices 
{
  One,
  Two,
  Three,
}

public class Element 
{
  List<Choices> _allowedChoices;
  [XmlAttribute]
  public List<Choices> AllowedChoices
  {
    get {return _allowedChoices ?? ( _allowedChoices = new List<Choices>() );}
    set { _allowedChoices = value; }
  }
}

[Test]
public void testing_empty_enum_list_serialization()
{
    var ser = new XmlSerializer(typeof (Element));
    using (var sw = new StringWriter())
    {
        ser.Serialize(sw, new Element
        {
            AllowedChoices = {},
        });
        var text = sw.ToString();
        Console.WriteLine(text);
        using (var sr = new StringReader(text))
        {
            var deserialized  = (Element) ser.Deserialize(sr);
        }
    }
}

If I use the XmlSerializer to serialize this to xml I get:

( Note the empty AllowedChoices attribute at the end )

<?xml version="1.0" encoding="utf-16"?>
<Element xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" AllowedChoices="" />

If I then use the XmlSerializer to deserialize this xml I something like:

System.InvalidOperationException : There is an error in XML document (2, 109).
  ----> System.InvalidOperationException : Instance validation error: '' is not a valid value for Choices.

This is an empty list of enums that serializes without error, Y U NO deserialize!?

Remco Schoeman
  • 515
  • 7
  • 12

1 Answers1

1

I've found these related questions, which fail for expected reasons, namely that an enum does not have a null default value, which is a clue...

deserializing enums

XmlSerializer enumeration deserialization failing on (non existent) whitespace

And this is the solution:

If the implementation of AllowedChoices is an auto-property and is not initialized in the constructor (i.e. it's null when deserialization gets to that property) it works as expected, and does not bomb on deserialization.

I have full control over the source, so I'm going to be pragmatic and add an None value to my Choices enum with a [XmlEnum("")] attribute, and treat the list as empty if that's the only value in the list instead of not doing auto-initialization of the list.

See http://tech.pro/blog/1370/why-collections-should-never-be-null for why I want that.

Bonus tip:

If you want to create an empty-string of an enum alias do it like this:

public enum Choices
{
    [XmlEnum("default")]
    Default = 0,

    [XmlEnum("")]
    DefaultAlias = Default,
}
Community
  • 1
  • 1
Remco Schoeman
  • 515
  • 7
  • 12