问题
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
?
回答1:
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 [][].
回答2:
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.
回答3:
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.
来源:https://stackoverflow.com/questions/2085689/xmlserializer-bug-when-serializing-collection-of-collections-without-root-elemen