views:

129

answers:

1

I have the following model:

public class ABaseObject
{
    private Guid id = Guid.NewGuid();

    public ABaseObject()
    {
    }

    public Guid ID { get { return id; } }
}

public class ADerivedObject : ABaseObject
{
    public ADerivedObject()
    {
    }

    public string Name { get; set; }
}

public class AObjectCollection<T>
{
    private List<T> items = new List<T>();

    public AObjectCollection()
    {
    }

    public IEnumerable<T> Items { get { return items; } }
    public void Add(T item)
    {
        items.Add(item);
    }

    public void Save(string filePath)
    {
        FileStream writer = new FileStream(filePath, FileMode.Create);
        DataContractSerializer s = new DataContractSerializer(typeof(T));
        s.WriteObject(writer, this);
        writer.Close();
    }

    public void Load(string filePath)
    {
        FileStream fs = new FileStream(filePath, FileMode.Open);
        XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
        DataContractSerializer ser = new DataContractSerializer(typeof(T));

        // Deserialize the data and read it from the instance.
        T deserializedObj = (T)ser.ReadObject(reader, true);
        reader.Close();
        fs.Close();
    }
}

So basically I want to be able to do the following:

var der = new ADerivedObject();
der.Name = "Test";
var col = new AObjectCollection<ADerivedObject>();
col.Add(der);
col.Save("C:\MyCollection.xml");
...
var col2 = new AObjectCollection<ADerivedObject>();
col2.Load("C:\MyCollection.xml");

When serialized it should look something like:

<Collection>
    <Item>
        <ID></ID>
        <Name></Name>
    </Item>
</Collection>

I have played around with DataContracts and XmlSerializer but I can't quite seem to find a way to do it.

+1  A: 

This code:

public class ABaseObject
{
    public ABaseObject() { }
    public Guid ID { get; set;}
}

[XmlType("Item")]
public class ADerivedObject : ABaseObject
{
    public ADerivedObject() {}
    public string Name { get; set; }
}

[XmlType("Collection")]
public class AObjectCollection<T>
{
    private System.Xml.Serialization.XmlSerializerNamespaces ns;
    private System.Xml.Serialization.XmlSerializer s;

    public AObjectCollection()
    {
        ns= new System.Xml.Serialization.XmlSerializerNamespaces();
        ns.Add( "", "");
        s= new System.Xml.Serialization.XmlSerializer(this.GetType());
        Items = new List<T>();
    }

    public List<T> Items { get; set; }
    public DateTime LastSaved { get;set; }

    public void Add(T item)
    {
        Items.Add(item);
    }

    public void Save(string filePath)
    {
        LastSaved= System.DateTime.Now;
        var xmlws = new System.Xml.XmlWriterSettings { OmitXmlDeclaration = true, Indent= true };

        using ( var writer = System.Xml.XmlWriter.Create(filePath, xmlws))
        {
            s.Serialize(writer, this, ns);
        }
    }

    public static AObjectCollection<T2> Load<T2>(string filepath)
    {
        AObjectCollection<T2> obj;
        try
        {
            var s= new System.Xml.Serialization.XmlSerializer(typeof(AObjectCollection<T2>));
            using(System.IO.StreamReader reader= System.IO.File.OpenText(filepath))
            {
                obj= (AObjectCollection<T2>) s.Deserialize(reader);
            }
        }
        catch
        {
            obj= new AObjectCollection<T2>();
        }

        return obj;
    }
}

produces this output:

<Collection>
  <Items>
    <Item>
      <ID>00000000-0000-0000-0000-000000000000</ID>
      <Name>Test</Name>
    </Item>
  </Items>
  <LastSaved>2010-02-04T07:32:05.812-05:00</LastSaved>
</Collection>

There are ways to tweak the XML to remove the Collection/Items layer. Search SO for other Collection / Serialization questions.

Cheeso
Thanks this is pretty much what I wanted.
James
Just out of curiosity, is it possible to achieve the same format using DataContracts instead of XML serializer? After some research I see that DataContracts are far quicker.
James
Ok I was able to replicate this using DataContracts. However in the XML it is showing the elements like <d1p1:Items... Any idea's why?
James
d1p1 is a namespace prefix. Try posting a new question. Also, I'm not sure it's correct that the DataContractSerializer is far quicker than the XML Serializer. I've read that, too, but have never seen test results upholding the claim. Have you tested it?
Cheeso
@Cheeso, no but I had a quick look @ marc gravels protobuf-net project and he has benchmark test results on there and by the looks of it DataContractSerializer is far superior performance wise. Have a look http://code.google.com/p/protobuf-net/wiki/Performance
James