{"id":4965,"date":"2014-03-30T17:14:00","date_gmt":"2014-03-30T17:14:00","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/how-to-properly-xml-serialize-collections-with-an-extensible-object-hierarchy-in-net-collection-of-common-programming-errors\/"},"modified":"2014-03-30T17:14:00","modified_gmt":"2014-03-30T17:14:00","slug":"how-to-properly-xml-serialize-collections-with-an-extensible-object-hierarchy-in-net-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2014\/03\/30\/how-to-properly-xml-serialize-collections-with-an-extensible-object-hierarchy-in-net-collection-of-common-programming-errors\/","title":{"rendered":"How to properly XML-serialize collections with an extensible object hierarchy in .NET?-Collection of common programming errors"},"content":{"rendered":"<ul>\n<li><img decoding=\"async\" src=\"http:\/\/www.gravatar.com\/avatar\/822946942061078fe89f96f4088964b0?s=32&amp;d=identicon&amp;r=PG\" \/><br \/>\nOded<\/p>\n<p>Scenario:<\/p>\n<ol>\n<li>I got 4 classes, <code>Configuration<\/code>, <code>Option<\/code>, <code>Option1<\/code> and <code>Option2<\/code><\/li>\n<li><code>Option1<\/code> and <code>Option2<\/code> inherit from <code>Option<\/code><\/li>\n<li><code>Configuration<\/code> has a property that is of type <code>List<\/code>, in which I intend to store objects that descend from <code>Option<\/code><\/li>\n<li><code>Option<\/code> is abstract, and will never be used to construct an actual instance.<\/li>\n<\/ol>\n<p>The problem:<\/p>\n<ul>\n<li>When I simply annotate these objects and members with simple <code>[XmlType(...)]<\/code> and <code>[XmlElement(...)]<\/code> attributes, the serialization of the objects in the collection ends up different than what I want<\/li>\n<li>If I add the necessary <code>[XmlArray(...)]<\/code> and <code>[XmlArrayItem(...)]<\/code> attributes, it looks like I want, but then I have to specify at compile-time a known list of item types, making extensibility impossible<\/li>\n<\/ul>\n<p>Here&#8217;s an example LINQPad script that you can run:<\/p>\n<pre><code>void Main()\n{\n\n    var Configuration = new Configuration();\n    Configuration.Options.Add(new Option1());\n    Configuration.Options.Add(new Option2());\n\n    var serializer = new XmlSerializer(typeof(Configuration), new Type[]\n    {\n        typeof(Option1),\n        typeof(Option2),\n    });\n    var ns = new XmlSerializerNamespaces();\n    ns.Add(string.Empty, string.Empty);\n\n    using (var writer = new StringWriter())\n    {\n        serializer.Serialize(writer, Configuration, ns);\n        writer.ToString().Dump();\n    }\n}\n\n[XmlType(\"configuration\")]\npublic class Configuration\n{\n    private readonly List _Options = new List();\n\n    [XmlElement(\"options\")]\n    public List Options { get { return _Options; } }\n\n    [XmlArray(\"options2\")]\n    [XmlArrayItem(typeof(Option1))]\n    [XmlArrayItem(typeof(Option2))]\n    public List Options2 { get { return _Options; } }\n}\n\npublic class Option { }\n\n[XmlType(\"option1\")]\npublic class Option1 : Option { }\n\n[XmlType(\"option2\")]\npublic class Option2 : Option { }\n<\/code><\/pre>\n<p>When you run this, you get the following output:<\/p>\n<pre><code>\n\n  \n  \n  \n    \n    \n  \n\n<\/code><\/pre>\n<p>Notice how the first property, <code>options<\/code> is serialized quite different from <code>options2<\/code>, but they have the same content.<\/p>\n<p>Basically, I&#8217;d like to have the serialized xml look like <code>options2<\/code>, but without having to specify the allowed type of classes through attributes, since this will make extensibility impossible.<\/p>\n<p>If I have to provide them through something that can be altered at runtime, that&#8217;s fine, but hardcoded at compile-time is a no-go.<\/p>\n<\/li>\n<li><img decoding=\"async\" src=\"http:\/\/graph.facebook.com\/100000653737180\/picture?type=large\" \/><br \/>\nMarc Gravell<\/p>\n<p>I think you are going to have to look at <code>XmlAttributeOverrides<\/code>, which lets you supply the attributes at runtime. This is not <em>trivial<\/em>, but not mind-melting either. The biggest catch: when you use the constructor that accepts <code>XmlAttributeOverrides<\/code> an assembly is generated <strong>every time<\/strong>, so be sure to cache and re-use the <code>XmlSerializer<\/code> instance &#8211; otherwise you will leak assemblies (they can&#8217;t be collected).<\/p>\n<p>To implement you would have an <code>XmlAttributes<\/code> instance to which you tweak <code>XmlArray<\/code> and <code>XmlArrayItems<\/code>, then use <code>XmlAttributeOverrides.Add(Type,Member,XmlAttributes)<\/code> to associate that with <code>\"Options2\"<\/code>.<\/p>\n<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Oded Scenario: I got 4 classes, Configuration, Option, Option1 and Option2 Option1 and Option2 inherit from Option Configuration has a property that is of type List, in which I intend to store objects that descend from Option Option is abstract, and will never be used to construct an actual instance. The problem: When I simply [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4965","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/4965","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=4965"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/4965\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=4965"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=4965"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=4965"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}