Reputation: 391276
Scenario:
Configuration
, Option
, Option1
and Option2
Option1
and Option2
inherit from Option
Configuration
has a property that is of type List<Option>
, 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:
[XmlType(...)]
and [XmlElement(...)]
attributes, the serialization of the objects in the collection ends up different than what I want[XmlArray(...)]
and [XmlArrayItem(...)]
attributes, it looks like I want, but then I have to specify at compile-time a known list of item types, making extensibility impossibleHere's an example LINQPad script that you can run:
void Main()
{
var Configuration = new Configuration();
Configuration.Options.Add(new Option1());
Configuration.Options.Add(new Option2());
var serializer = new XmlSerializer(typeof(Configuration), new Type[]
{
typeof(Option1),
typeof(Option2),
});
var ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
using (var writer = new StringWriter())
{
serializer.Serialize(writer, Configuration, ns);
writer.ToString().Dump();
}
}
[XmlType("configuration")]
public class Configuration
{
private readonly List<Option> _Options = new List<Option>();
[XmlElement("options")]
public List<Option> Options { get { return _Options; } }
[XmlArray("options2")]
[XmlArrayItem(typeof(Option1))]
[XmlArrayItem(typeof(Option2))]
public List<Option> Options2 { get { return _Options; } }
}
public class Option { }
[XmlType("option1")]
public class Option1 : Option { }
[XmlType("option2")]
public class Option2 : Option { }
When you run this, you get the following output:
<?xml version="1.0" encoding="utf-16"?>
<configuration>
<options d2p1:type="option1" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance" />
<options d2p1:type="option2" xmlns:d2p1="http://www.w3.org/2001/XMLSchema-instance" />
<options2>
<option1 />
<option2 />
</options2>
</configuration>
Notice how the first property, options
is serialized quite different from options2
, but they have the same content.
Basically, I'd like to have the serialized xml look like options2
, but without having to specify the allowed type of classes through attributes, since this will make extensibility impossible.
If I have to provide them through something that can be altered at runtime, that's fine, but hardcoded at compile-time is a no-go.
Upvotes: 2
Views: 291
Reputation: 1062502
I think you are going to have to look at XmlAttributeOverrides
, which lets you supply the attributes at runtime. This is not trivial, but not mind-melting either. The biggest catch: when you use the constructor that accepts XmlAttributeOverrides
an assembly is generated every time, so be sure to cache and re-use the XmlSerializer
instance - otherwise you will leak assemblies (they can't be collected).
To implement you would have an XmlAttributes
instance to which you tweak XmlArray
and XmlArrayItems
, then use XmlAttributeOverrides.Add(Type,Member,XmlAttributes)
to associate that with "Options2"
.
Upvotes: 2