views:

136

answers:

3

This is a bit of a long question, but I've made it as terse as possible, so please bear with me. It looks to me like a bug in the XmlSerializer class but before I file it with Microsoft I'd like to see if there's anything I've missed, which is entirely possible.

I'm attempting to generate the following XML as a representative case, which is essentially a collection of collections, but where the outer collection has additional elements:

<Links>
  <Name />
  <Group>
    <Link />
    <Link />
  </Group>
  <Group>
    <Link />
    <Link />
  </Group>
</Links>

The serialization classes are as follows:

public class Link { }

public class Links
{
    public string Name { get; set; }

    [XmlElement("Group")]
    public Link[][] Groups { get; set; }
}

And a simple test program to run it is as follows:

class Program
{
    static void Main()
    {
        var serializer = new XmlSerializer(typeof(Links));
        var links = new Links { Name = "", Groups = new[] { 
            new[] { new Link(), new Link() }, 
            new[] { new Link(), new Link() } } };
        serializer.Serialize(Console.Out, links);
    }
}

This employs the trick of using XmlElement to remove the parent node of the collection, which should mean that no <Groups> element is emitted, and for each object contained in the outer array (which will be of type Link[]) a <Group> element should be emitted. However, at runtime, this gives the following exception from the XmlSerializer:

Unable to generate a temporary class (result=1). error CS0030: Cannot convert type 'Link[][]' to 'Link[]' error CS0029: Cannot implicitly convert type 'Link[]' to 'Link[][]'

My guess is that the serializer is for some reason attempting to flatten the collection, and thinks that the type contained in the outer array is Link rather than Link[] which causes the compilation failure of its serialization classes as the types don't match.

What do you think? Is this a bug? And is there a workaround to generate the XML I'm after using the XmlSerializer?

A: 

For what I see, the problem is exactly where the error say.

The way you wrote the desired XML for the class you're trying to serialize, show that Group is a collection of Links; however, it's defined as a jagged array of links (that is an array of arrays).

I believe you revert it to a simple array, the problem will be solved.


Edited to Add

If you really need to have the XML you specified, you could implement the IXmlSerializable interface and create AND read the XML yourself.

It's always a solution when things doesn't work the way we expect.

Paulo Santos
If I revert it to a simple array then it will not be a collection of collections, it will merely be a collection and there will only be one `Group` element, not multiple ones. The `Groups` property contains *multiple* groups, not one.
Greg Beech
Then I'd make Groups as a `List<Link[]>`
Paulo Santos
`List<Link[]>` doesn't solve it. You will only get another "group" called ArrayOfLink since you cannot specify what the inner elements (the items of the List) should be called.
Peter Lillevold
+1  A: 

I'm able to get almost the same structure using the XmlArrayItem attribute:

[XmlArrayItem(ElementName = "Group", Type = typeof(Link[]))]
Link[][] Groups;

but I still get a top-level Groups element. At least serialization of the jagged array works this way.

As far as my tests go, there is no way to get the XmlElement attribute to work with jagged arrays. Whether this is a bug or a "feature" I'm not sure. I would agree that, judging by the error message, this looks like a bug. At least it should throw that XmlElement with jagged array properties are not supported instead of failing at trying to put [] into [][].

Peter Lillevold
Yes, I also tried with `[XmlArrayItem]` and here it does correctly identify that the contained type is a `Link[]` rather than a `Link` which is what made me believe it was probably a bug (although it's somewhat hard to say as the behaviour of `[XmlElement]` with regard to collection flattening isn't completely specified anywhere that I can see). I'll wait a bit and see if anybody else posts anything that can shed more light on it, but it seems you've confirmed my suspicions.
Greg Beech
+1  A: 

I would suggest writing an XML schema, which defines the syntax you want to have in your XML and than generate the corresponding serialization code from it using a code generation tool (e.g. MS xsd.exe). Writing a schema is a good approach for data validation anyway. Even if you do not want to use it later and rather want to maintain the code yourself, you can at least have a look at the generated code.

TheBigW
I've tried this... the generated code looks exactly as in the question, and then fails at runtime...
Greg Beech
Then I would suggest to write a bug report to MS anyway, as their XSD.exe tool is generating not working code.
TheBigW