views:

1157

answers:

6

I have structure like this:

public interface A
{
    public void method();
}

public class B : A
{
}

public class C : A
{
}

List<A> list;

List contains objects of type B and C they also have some fields that I would like to keep, can I now serialize it, deserialize back and get the proper object instances? Preferably to XML

EDIT:

Is there any simple way to serialize this list that contains interfaces, and then deserialize it back to B and C instances?

+1  A: 

Yes, but you have to play with the XmlElement, XmlRoot and XmlArray Attributes. Each Type needs it's own element name.

EDIT: Some sample code. All classes are derived from a common base class.

Here is a sample code:

[XmlRoot(ElementName="Root")]
public sealed class SomeObject
{

    private BaseObject _Object;

    [XmlElement(Type=typeof(App.Projekte.Projekt), ElementName="Projekt")]
    [XmlElement(Type=typeof(App.Projekte.Task), ElementName="Task")]
    [XmlElement(Type=typeof(App.Projekte.Mitarbeiter), ElementName="Mitarbeiter")]
    public BaseObject Object
    {
        get
        {
            return _Object;
        }
        set
        {
            _Object = value;
        }
    }
}

EDIT: Remove Serialization Attribute as it's not needed (but is needed in my project where the code is from)

Arthur
You don't need `[Serializable]`. It's not used by XML Serialization.
John Saunders
+2  A: 

Assuming you're using the built in .net XML serialization you should take a look at the following attribute:

System.Xml.Serialization.XmlIncludeAttribute

It allows you to instruct the serializer to include other types when serializing/deserializing.

Adding new types to the list and not updating the serialization meta data is a common source of mistakes, make sure you have adequate test coverage.

jonnii
A: 

For your case make an abstract class that implements your interface like:

abstract class Abs : A

and then derive your classes from Abs

public class B : Abs
public class C : Abs

and List list;

now use XmlIncludeAttribute to add your types into the XmlSerializer's type array.

viky
+3  A: 

I would use an abstract class instead of an interface (as one cannot serialize a type of interface), then instead of hard coding the type using the XmlInclude attribute, I would add the known types to the XmlSerializer in the Serial and Deserialize methods like so:

    string listXml = Serialize<List<A>>(ListA, new Type[] { typeof(B), typeof(C) });

    List<IA> NewList = Deserialize<List<A>>(listXml, new Type[] { typeof(B), typeof(C) });

    private static T Deserialize<T>(string Xml, Type[] KnownTypes)
    {
        XmlSerializer xs = new XmlSerializer(typeof(T),KnownTypes);

        StringReader sr = new StringReader(Xml);
        return (T)xs.Deserialize(sr);
    }

    private static string Serialize<T>(Object obj, Type[] KnownTypes)
    {
        StringBuilder sb = new StringBuilder();
        using (StringWriter sw = new StringWriter(sb))
        {
            XmlSerializer xs = new XmlSerializer(typeof(T), KnownTypes);

            xs.Serialize(sw, obj);
        }
        return sb.ToString();
    }
CkH
A: 

XmlSerializer does not work with interfaces. So you can:

Convert interface to abstract class and then use XmlIncludeAttribute for it or provide KnownTypes to XmlSerializer

or

Implement IXmlSerializable for the parent type

or

Consider using DataContractSerializer from .NET 3.0

+1  A: 

You may try using DataContractSerializer:

public interface A
{
}

public class B : A
{
}

public class C : A
{
}

class Program
{
    static void Main(string[] args)
    {
        List<A> list = new List<A>(new A[] { new B(), new C() });
        var serializer = new DataContractSerializer(
            list.GetType(), new[] { typeof(B), typeof(C) });

        var sb = new StringBuilder();
        using (var stringWriter = new StringWriter(sb))
        using (var writer = XmlWriter.Create(stringWriter))
        {
            serializer.WriteObject(writer, list);
        }

        using (var stringReader = new StringReader(sb.ToString()))
        using (var reader = XmlReader.Create(stringReader))
        {
            list = (List<A>)serializer.ReadObject(reader);
        }

    }
}
Darin Dimitrov