Reputation: 12649
I got an object that has to inherit from a general interface as well as it has a list from that interface as property.
Going to serialize it follows by problems, as the XmlSerialzer is not able to determine the real types that are inside of my MyClass.Items
list elements.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace MyTest
{
public interface IMyInterface
{
string TestProperty { get; set; }
}
public class MyClass : IMyInterface
{
public string TestProperty { get; set; }
public List<IMyInterface> Items { get; set; }
}
class Program
{
static void Main(string[] args)
{
MyClass obj = new MyClass() { TestProperty = "Test" };
XmlSerializer xs = new XmlSerializer(typeof(MyClass)); // <- throws System.NotSupportedException
using (XmlWriter xw = XmlWriter.Create("file.xml", new XmlWriterSettings()
{
Encoding = Encoding.UTF8,
Indent = true,
NewLineHandling = NewLineHandling.Entitize
}))
{
xs.Serialize(xw, obj);
}
}
}
}
How can I serialize a List<T>
where T is an interface?
Upvotes: 2
Views: 1947
Reputation: 12649
So, based on decPLs answer I've created a class to do this job. T
must be an interface and it will work:
public class InterfaceCollection<T> : Collection<T>, IXmlSerializable where T : class
{
private string Namespace { get; set; }
private string Assembly { get; set; }
public InterfaceCollection()
{
}
public InterfaceCollection(IList<T> list, string namespaceOfInheritedTypes = null, string assemblyOfInheritedTypes = null)
: base(list)
{
this.Namespace = namespaceOfInheritedTypes ?? null;
this.Assembly = assemblyOfInheritedTypes ?? null;
}
public InterfaceCollection(string namespaceOfInheritedTypes, string assemblyOfInheritedTypes = null)
{
this.Namespace = namespaceOfInheritedTypes ?? null;
this.Assembly = assemblyOfInheritedTypes ?? null;
}
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
this.Namespace = reader.GetAttribute("fromNamespace");
this.Assembly = reader.GetAttribute("fromAssembly");
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
Type type;
if (this.Assembly != null)
{
type = Type.GetType(this.Namespace + "." + reader.Name + ", " + this.Assembly);
}
else
{
type = Type.GetType(this.Namespace + "." + reader.Name);
}
if (type != null)
{
XmlSerializer xs = XmlSerializer.FromTypes(new[] { type })[0];
this.Items.Add((T)xs.Deserialize(reader));
}
}
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("fromNamespace", this.Namespace);
if (this.Assembly != null) writer.WriteAttributeString("fromAssembly", this.Assembly);
foreach (T element in this)
{
Type type = element.GetType();
XmlSerializer xs = XmlSerializer.FromTypes(new[] { type })[0];
xs.Serialize(writer, element);
}
}
}
Upvotes: 1
Reputation: 5402
Unfortunately it's not supported out of the box, but it's doable. You would have to use the IXmlSerializable
interface and write your custom serialization. It shouldn't be that much difficult - you'd need to enumerate through your list, get the underlying type of each object and create a new XmlSerializer
for this type. Deserialization could be a bit more tricky, as you'd need to parse the class names to determine runtime types.
Upvotes: 1