代码之家  ›  专栏  ›  技术社区  ›  Steve

XmlSerializer序列化接口的通用列表

  •  12
  • Steve  · 技术社区  · 15 年前

        public interface IAnimal
        {
            int Age();
        }
        public class Dog : IAnimal
        {
            public int Age()
            {
                return 1;
            }
        }
        public class Cat : IAnimal
        {
            public int Age()
            {
                return 1;
            }
        }
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            var animals = new List<IAnimal>
            {
                new Dog(),
                new Cat()
            };
    
            var x = new XmlSerializer(animals.GetType());
            var b = new StringBuilder();
            var w = XmlTextWriter.Create(b, new XmlWriterSettings { NewLineChars = "\r\n", Indent = true });
            //FAIL - cannot serialize interface. Does easy way to do this exist?
            x.Serialize(w, animals);
            var s = b.ToString();    
        }
    
    5 回复  |  直到 11 年前
        1
  •  14
  •   Alex Paven    15 年前

    您也可以使用XmlSerializer,但是您需要包含所有可能出现在正在序列化的对象图中的类型,这会限制可扩展性并降低可维护性。您可以通过使用XmlSerializer的构造函数的重载来完成:

    var x = new XmlSerializer(animals.GetType(), new Type[] { typeof(Cat), typeof(Dog) });
    

    另外,在使用XmlSerializer时有几个值得注意的问题,所有这些问题 here (MSDN) -例如,查看标题“动态生成的程序集”。

        2
  •  8
  •   Stephen Turner    12 年前

    这个 XmlSerializer IXmlSerializable 接口。这允许您记录类型,以便可以重新创建(反序列化)它。

    ListOfIAnimal 下面的类显示了我是如何继承和扩展泛型列表的 List<IAnimal> 实现所需的接口。我压扁了您的旧类,为每个类添加了一个额外的非接口字段,这样我就可以看到具体的类被正确地序列化和反序列化了。

    与你的代码相比,我只是使用了新的类型 列表<IAnimal> ,其他的变化只是一点重构。

    它的完整代码,只需将其复制到自己的.cs文件中,调用第一个函数来逐步完成它。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Xml;
    using System.Xml.Serialization;
    
    namespace Serialiser
    {
        static class SerialiseInterface
        {
            public static void SerialiseAnimals()
            {
                String finalXml;
    
                // Serialize
                {
                    var animals = new ListOfIAnimal{
                        new Dog() { Age = 5, Teeth = 30 },
                        new Cat() { Age = 6, Paws = 4 }
                    };
    
                    var xmlSerializer = new XmlSerializer(animals.GetType());
                    var stringBuilder = new StringBuilder();
                    var xmlTextWriter = XmlTextWriter.Create(stringBuilder, new XmlWriterSettings { NewLineChars = "\r\n", Indent = true });
                    xmlSerializer.Serialize(xmlTextWriter, animals);
                    finalXml = stringBuilder.ToString();
                }
    
                // Deserialise
                {
                    var xmlSerializer = new XmlSerializer(typeof(ListOfIAnimal));
                    var xmlReader = XmlReader.Create(new StringReader(finalXml));
                    ListOfIAnimal animals = (ListOfIAnimal)xmlSerializer.Deserialize(xmlReader);
                }
            }
        }
    
        public class ListOfIAnimal : List<IAnimal>, IXmlSerializable
        {
            public ListOfIAnimal() : base() { }
    
            #region IXmlSerializable
            public System.Xml.Schema.XmlSchema GetSchema() { return null; }
    
            public void ReadXml(XmlReader reader)
            {
                reader.ReadStartElement("ListOfIAnimal");
                while (reader.IsStartElement("IAnimal"))
                {
                    Type type = Type.GetType(reader.GetAttribute("AssemblyQualifiedName"));
                    XmlSerializer serial = new XmlSerializer(type);
    
                    reader.ReadStartElement("IAnimal");
                    this.Add((IAnimal)serial.Deserialize(reader));
                    reader.ReadEndElement(); //IAnimal
                }
                reader.ReadEndElement(); //ListOfIAnimal
            }
    
            public void WriteXml(XmlWriter writer)
            {
                foreach (IAnimal animal in this)
                {
                    writer.WriteStartElement("IAnimal");
                    writer.WriteAttributeString("AssemblyQualifiedName", animal.GetType().AssemblyQualifiedName);
                    XmlSerializer xmlSerializer = new XmlSerializer(animal.GetType());
                    xmlSerializer.Serialize(writer, animal);
                    writer.WriteEndElement();
                }
            }
            #endregion
        }
    
        public interface IAnimal { int Age { get; set; } }
        public class Dog : IAnimal { public int Age { get; set;} public int Teeth { get; set;} }
        public class Cat : IAnimal { public int Age { get; set;} public int Paws { get; set;} }
    }
    

    我想把反序列化作为一个练习留给读者,但是没有反序列化的代码将非常有用。

        3
  •  3
  •   Aliostad    15 年前

    XmlSerializer ? 这是一个已知的问题 XmlSerializer .

    BinaryFormatter bf = new BinaryFormatter();
    MemoryStream ms = new MemoryStream();
    bf.Serialize(ms, animals);
    

    另一种选择是使用WCF DataContractSerializer

        4
  •  2
  •   Wojciech Nagórski    9 年前

    你可以用 ExtendedXmlSerializer .

    var serializer = new ExtendedXmlSerializer();
    var xml = serializer.Serialize(animals);
    

    您的xml将如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <ArrayOfIAnimal>
        <Dog type="Model.Dog" />
        <Cat type="Model.Cat" />
    </ArrayOfIAnimal>
    
        5
  •  0
  •   D. Kermott    9 年前

    简单的方法是将[Serializable()]装饰添加到类中 并将IList更改为List,看看是否有效。

    如果你使用界面,那么去看看webturner的答案。

    推荐文章