简体   繁体   中英

XML Serialization of class collection in c#

I have a class containing a collection of objects. The objects in the collection are descendants of the same class. Class A is the base class and Class B and Class C inherit from Class A. B and C each have some differing members. The collection is a LIst collection.

I would like to serialize the class containing the collection. How do I attribute the different classes to be able to serialize and deserialize the xml file?

Thanks, Robert

[Serializable] attribute is irrelevant in XML serialization. The XML serializer serializes the properties with public getter AND setter. Moreover, you'll have to tell to the XML serializer the extra types it could use, those which aren't known statically, by passing a Type[] extra argument to the serializer ctor or adding [XmlInclude(typeof(B))] and [XmlInclude(typeof(C))]

EDIT :

The following code :

[XmlInclude(typeof(B))]
[XmlInclude(typeof(C))]
public class A
{
    public int Value;
    public A() { }
    public A(int i) { Value = i; }
}

public class B : A
{
    public double DoubleValue;
    public B() { }
    public B(int i, double d) : base(i) { DoubleValue = d; }
}

public class C : A
{
    public string StringValue;
    public C() { }
    public C(int i, string s) : base(i) { StringValue = s; }
}

public class Container
{
    public List<A> Items;
    public Container()
    {
        Items = new List<A>();
    }
}

class Program
{
    static void Main(string[] args)
    {
        Container container = new Container();
        container.Items.Add(new B(0, 1.3d));
        container.Items.Add(new B(1, 0.37d));
        container.Items.Add(new C(2, "c"));

        using (System.IO.StreamWriter writer = new System.IO.StreamWriter(@"C:\TEMP\Container.xml"))
        {
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Container));
            serializer.Serialize(writer, container);
        }
    }
}

produces that xml :

<Container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Items>
    <A xsi:type="B">
      <Value>0</Value>
      <DoubleValue>1.3</DoubleValue>
    </A>
    <A xsi:type="B">
      <Value>1</Value>
      <DoubleValue>0.37</DoubleValue>
    </A>
    <A xsi:type="C">
      <Value>2</Value>
      <StringValue>c</StringValue>
    </A>
  </Items>
</Container>

You can either use XmlSerialization or DataContract (or a more 'primitive' implementation), see: http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/

As for serialization: you only need to mark the classes you want to serialize, so you need to mark Class B and C but you are not required to mark class A.

I would however recommend you to mark class A as serializable and therefore make it more clear to you and other programmers that this class supports serialization.

You do not need to attribute classes to use Xml serialization:

using System;
using System.IO;
using System.Xml.Serialization;

/* Three classes are included here. Each one will
be used to create three XmlSerializer objects. */

public class Instrument
{
   public string InstrumentName;
}

public class Player
{
   public string PlayerName;
}

public class Piece
{
   public string PieceName;
}

public class Test
{
   public static void Main()
   {
      Test t = new Test();
      t.GetSerializers();
   }

   public void GetSerializers()
   {
      // Create an array of types.
      Type[]types = new Type[3];
      types[0] = typeof(Instrument);
      types[1] = typeof(Player);
      types[2] = typeof(Piece);

      // Create an array for XmlSerializer objects.
      XmlSerializer[]serializers= new XmlSerializer[3];
      serializers = XmlSerializer.FromTypes(types);
      // Create one Instrument and serialize it.
      Instrument i = new Instrument();
      i.InstrumentName = "Piano";
      // Create a TextWriter to write with.
      TextWriter writer = new StreamWriter("Inst.xml");
      serializers[0].Serialize(writer,i);
      writer.Close();
   }
}

To use a collection, you can serialise it as follows:

using System;
using System.IO;
using System.Collections;
using System.Xml.Serialization;

public class Test{
    static void Main(){
        Test t = new Test();
        t.SerializeCollection("coll.xml");
    }

    private void SerializeCollection(string filename){
        Employees Emps = new Employees();
        // Note that only the collection is serialized -- not the 
        // CollectionName or any other public property of the class.
        Emps.CollectionName = "Employees";
        Employee John100 = new Employee("John", "100xxx");
        Emps.Add(John100);
        XmlSerializer x = new XmlSerializer(typeof(Employees));
        TextWriter writer = new StreamWriter(filename);
        x.Serialize(writer, Emps);
    }
}
public class Employees:ICollection{
    public string CollectionName;
    private ArrayList empArray = new ArrayList(); 

    public Employee this[int index]{
        get{return (Employee) empArray[index];}
    }

    public void CopyTo(Array a, int index){
        empArray.CopyTo(a, index);
    }
    public int Count{
        get{return empArray.Count;}
    }
    public object SyncRoot{
        get{return this;}
    }
    public bool IsSynchronized{
        get{return false;}
    }
    public IEnumerator GetEnumerator(){
        return empArray.GetEnumerator();
    }

    public void Add(Employee newEmployee){
        empArray.Add(newEmployee);
    }
}

public class Employee{
    public string EmpName;
    public string EmpID;
    public Employee(){}
    public Employee(string empName, string empID){
        EmpName = empName;
        EmpID = empID;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM