简体   繁体   中英

Serialize list of interfaces using XML Serialization

I have the class below which I need to serialize using the XML Serializer

I know that the XML serializer does not like interfaces

However, our coding standards normally involve always coding to interfaces not concrete classes

I thought of a way to be able to stream this list without changing the types which would cause many compilation issues, as well as breaking our standards

My idea is to have a property which reads the Meters list and casts to concrete classes then to totally ignore meters when it comes to serializing

However, the XML will still need to have Meters as the element name

However this does not work

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Xml.Serialization;

    public class MeterWalkOrder
    {
        public MeterWalkOrder()
        {
            Meters = new List<IMeter>();
        }

        public String Name { get; set; }


        [XmlIgnore]
        public List<IMeter> Meters { get; set; }

        [XmlArrayItem(ElementName = "Meter")]
        [XmlElement(ElementName = "Meters")]
        public List<Meter> SerializableMeters
        {
            get
            {
                return Meters.Cast<Meter>().ToList();
            }
            set
            {
                Meters = new List<IMeter>(value);                
            }
        }
    }
}

Is there any way around this?

My XML (which cannot be changed) is below

   <MeterWalkOrder>
      <Name>Red Route</Name>
      <Meters>
        <Meter>
          <MeterID>1</MeterID>
          <SerialNumber>12345</SerialNumber>
        </Meter>
        <Meter>
          <MeterID>2</MeterID>
          <SerialNumber>SE</SerialNumber>
        </Meter>
      </Meters>
    </MeterWalkOrder>

The top level error is

There was an error reflecting type 'WindowsFormsApplication1.Classes.MeterWalkOrder'.

The inner exception is

{"XmlElement, XmlText, and XmlAnyElement cannot be used in conjunction with XmlAttribute, XmlAnyAttribute, XmlArray, or XmlArrayItem."}

I really would like to avoid setting a precedent for using lists of concrete classes

You will need to replace [XmlElement(ElementName = "Meters")] with [XmlArray(ElementName = "Meters")] as the error states:

{"XmlElement, XmlText, and XmlAnyElement cannot be used in conjunction with XmlAttribute, XmlAnyAttribute, XmlArray, or XmlArrayItem."}

To define an Array for the XmlSerializer you can mark it with XmlArray and its corresponding items with XmlArrayItem

Example:

public class MeterWalkOrder
{
    public MeterWalkOrder()
    {
        Meters = new List<IMeter>();
    }

    public String Name { get; set; }

    [XmlIgnore]
    public List<IMeter> Meters { get; set; }

    [XmlArrayItem(ElementName = "Meter")]
    [XmlArray(ElementName = "Meters")]
    public List<Meter> SerializableMeters
    {
        get
        {
            return Meters.Cast<Meter>().ToList();
        }
        set
        {
            Meters = new List<IMeter>(value);                
        }
    }
}

 public interface IMeter {
   int MeterID { get; set; }
 }

 public class Meter : IMeter {
     public int MeterID { get; set; }
     public string SerialNumber { get; set; }
 }

Test:

var data = new MeterWalkOrder{ Name = "Red Route", Meters = new List<IMeter>
{
     new Meter{ MeterID = 1, SerialNumber = "12345"},
     new Meter{ MeterID = 2, SerialNumber = "SE"}
}};
using (var stream = new FileStream("C:\\Users\\Adam\\Desktop\\Test2.xml", FileMode.OpenOrCreate))
{
    XmlSerializer ser = new XmlSerializer(typeof(MeterWalkOrder));
    ser.Serialize(stream, data);
}

Result:

<?xml version="1.0"?>
<MeterWalkOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Red Route</Name>
  <Meters>
    <Meter>
      <MeterID>1</MeterID>
      <SerialNumber>12345</SerialNumber>
    </Meter>
    <Meter>
      <MeterID>2</MeterID>
      <SerialNumber>SE</SerialNumber>
    </Meter>
  </Meters>
</MeterWalkOrder>

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