C# XML序列化可序列化对象的通用列表

C# XML序列化可序列化对象的通用列表,c#,list,generics,xml-serialization,C#,List,Generics,Xml Serialization,我可以序列化可序列化对象的通用列表,而不必指定它们的类型 类似于下面这段代码背后的意图: List<ISerializable> serializableList = new List<ISerializable>(); XmlSerializer xmlSerializer = new XmlSerializer(serializableList.GetType()); serializableList.Add((ISerializable)PersonList);

我可以序列化可序列化对象的通用列表,而不必指定它们的类型

类似于下面这段代码背后的意图:

List<ISerializable> serializableList = new List<ISerializable>();

XmlSerializer xmlSerializer = new XmlSerializer(serializableList.GetType());

serializableList.Add((ISerializable)PersonList);

using (StreamWriter streamWriter = System.IO.File.CreateText(fileName))
{
    xmlSerializer.Serialize(streamWriter, serializableList);
}
个人列表只是一个
列表

不过这只是为了测试,所以我觉得细节不太重要。关键是我有一个或多个不同的对象,它们都是可序列化的。我想将它们全部序列化到一个文件中。我认为最简单的方法是将它们放在一个通用列表中,并一次性序列化该列表。但这不起作用

我也尝试了
List
,但在

无法序列化System.Xml.Serialization.IXmlSerializable,因为它没有无参数构造函数。

很抱歉缺少细节,但我是这方面的初学者,不知道需要什么细节。如果要求更多细节的人试图以一种能让我理解所需细节的方式作出回应,或者给出一个概述可能方向的基本答案,这将是很有帮助的


同样感谢到目前为止我得到的两个答案-如果没有这些想法,我本可以花更多的时间阅读。在这个网站上,人们的帮助之大令人惊讶。

我认为最好使用带有一般参数的方法,如以下所示:

public static void SerializeToXml<T>(T obj, string fileName)
{
    using (var fileStream = new FileStream(fileName, FileMode.Create))
    { 
        var ser = new XmlSerializer(typeof(T)); 
        ser.Serialize(fileStream, obj);
    }
}

public static T DeserializeFromXml<T>(string xml)
{
    T result;
    var ser = new XmlSerializer(typeof(T));
    using (var tr = new StringReader(xml))
    {
        result = (T)ser.Deserialize(tr);
    }
    return result;
}
publicstaticvoidtoxml(T obj,字符串文件名)
{
使用(var fileStream=newfilestream(文件名,FileMode.Create))
{ 
var ser=新的XmlSerializer(typeof(T));
序列化(fileStream,obj);
}
}
公共静态T反序列化FromXML(字符串xml)
{
T结果;
var ser=新的XmlSerializer(typeof(T));
使用(var tr=newstringreader(xml))
{
结果=(T)序列反序列化(tr);
}
返回结果;
}

我认为Dreas的方法是可以的。但是,另一种方法是使用一些静态帮助器方法,并在每个方法上实现IXmlSerializable,例如XmlWriter扩展方法和XmlReader方法,以将其读回

public static void SaveXmlSerialiableElement<T>(this XmlWriter writer, String elementName, T element) where T : IXmlSerializable
{
   writer.WriteStartElement(elementName);
   writer.WriteAttributeString("TYPE", element.GetType().AssemblyQualifiedName);
   element.WriteXml(writer);
   writer.WriteEndElement();
}

public static T ReadXmlSerializableElement<T>(this XmlReader reader, String elementName) where T : IXmlSerializable
{
   reader.ReadToElement(elementName);

   Type elementType = Type.GetType(reader.GetAttribute("TYPE"));
   T element = (T)Activator.CreateInstance(elementType);
   element.ReadXml(reader);
   return element;
}
public static void savexmlserialableelement(这个XmlWriter编写器,String elementName,T元素),其中T:IXmlSerializable
{
writer.writeStarElement(elementName);
WriteAttributeString(“TYPE”,element.GetType().AssemblyQualifiedName);
元素WriteXml(writer);
writer.writeedelement();
}
公共静态T ReadXmlSerializableElement(此XmlReader阅读器,String elementName),其中T:IXmlSerializable
{
reader.ReadToElement(elementName);
Type elementType=Type.GetType(reader.GetAttribute(“Type”);
T element=(T)Activator.CreateInstance(elementType);
ReadXml(reader);
返回元素;
}
如果直接使用XmlSerializer类,请尽可能提前创建序列化程序集,因为定期构造新的XmlSerializer可能会对性能造成很大影响

对于集合,您需要以下内容:

public static void SaveXmlSerialiazbleCollection<T>(this XmlWriter writer, String collectionName, String elementName, IEnumerable<T> items) where T : IXmlSerializable
{
   writer.WriteStartElement(collectionName);
   foreach (T item in items)
   {
      writer.WriteStartElement(elementName);
      writer.WriteAttributeString("TYPE", item.GetType().AssemblyQualifiedName);
      item.WriteXml(writer);
      writer.WriteEndElement();
   }
   writer.WriteEndElement();
}
public static void SaveXmlSerialiazbleCollection(此XmlWriter编写器、字符串集合名称、字符串元素名称、IEnumerable项),其中T:IXmlSerializable
{
writer.writeStarteElement(collectionName);
foreach(项目中的T项目)
{
writer.writeStarElement(elementName);
WriteAttributeString(“TYPE”,item.GetType().AssemblyQualifiedName);
item.WriteXml(编写器);
writer.writeedelement();
}
writer.writeedelement();
}
请参见:

可以序列化的项 可以使用XmlSerializer对以下项目进行序列化 类别:

  • 公共类的公共读/写属性和字段
  • 实现ICollection或IEnumerable的类
  • xmlement
    对象
  • XmlNode
    对象
  • 数据集
    对象

特别是,
ISerializable
[Serializable]
属性并不重要


既然你已经告诉我们你的问题是什么(“它不起作用”不是一个问题陈述),你就可以得到你实际问题的答案,而不是猜测

当序列化类型的集合,但实际上要序列化派生类型实例的集合时,需要让序列化程序知道实际要序列化的类型。对于
对象
的集合也是如此


您需要使用构造函数来给出可能的类型列表。

如果XML输出要求可以更改,则始终可以使用二进制序列化,这更适合处理异构对象列表。下面是一个例子:

private void SerializeList(List<Object> Targets, string TargetPath)
{
    IFormatter Formatter = new BinaryFormatter();

    using (FileStream OutputStream = System.IO.File.Create(TargetPath))
    {
        try
        {
            Formatter.Serialize(OutputStream, Targets);
        } catch (SerializationException ex) {
            //(Likely Failed to Mark Type as Serializable)
            //...
        }
}
private void序列化列表(列表目标,字符串TargetPath)
{
IFormatter Formatter=新的BinaryFormatter();
使用(FileStream OutputStream=System.IO.File.Create(TargetPath))
{
尝试
{
序列化(输出流,目标);
}catch(SerializationException-ex){
//(可能无法将类型标记为可序列化)
//...
}
}
用作:

[Serializable]
public class Animal
{
    public string Home { get; set; }
}

[Serializable]
public class Person
{
    public string Name { get; set; }
}


public void ExampleUsage() {

    List<Object> SerializeMeBaby = new List<Object> {
        new Animal { Home = "London, UK" },
        new Person { Name = "Skittles" }
    };

    string TargetPath = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "Test1.dat");

    SerializeList(SerializeMeBaby, TargetPath);
}
[可序列化]
公营动物
{
公共字符串Home{get;set;}
}
[可序列化]
公共阶层人士
{
公共字符串名称{get;set;}
}
public void示例用法(){
List SerializeMeBaby=新列表{
新动物{Home=“伦敦,英国”},
新人{Name=“Skittles”}
};
字符串TargetPath=Path.Combine(
GetFolderPath(Environment.SpecialFolder.ApplicationData),
“Test1.dat”);
SerializeList(SerializeMeBaby、TargetPath);
}

如果不指定所需类型,则无法序列化对象集合。必须将所需类型列表传递给
XmlSerializer
的构造函数(参数
extraTypes
):

下面
[Serializable]
public class Animal
{
    public string Home { get; set; }
}

[Serializable]
public class Person
{
    public string Name { get; set; }
}


public void ExampleUsage() {

    List<Object> SerializeMeBaby = new List<Object> {
        new Animal { Home = "London, UK" },
        new Person { Name = "Skittles" }
    };

    string TargetPath = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "Test1.dat");

    SerializeList(SerializeMeBaby, TargetPath);
}
List<object> list = new List<object>();
list.Add(new Foo());
list.Add(new Bar());

XmlSerializer xs = new XmlSerializer(typeof(object), new Type[] {typeof(Foo), typeof(Bar)});
using (StreamWriter streamWriter = System.IO.File.CreateText(fileName))
{
    xs.Serialize(streamWriter, list);
}
[XmlInclude(typeof(Foo)), XmlInclude(typeof(Bar))]
public class MyBaseClass
{
}
namespace Utils
{
    public static class SerializeUtil
    {
        public static void SerializeToFormatter<F>(object obj, string path) where F : IFormatter, new()
        {
            if (obj == null)
            {
                throw new NullReferenceException("obj Cannot be Null.");
            }

            if (obj.GetType().IsSerializable == false)
            {
                //  throw new 
            }
            IFormatter f = new F();
            SerializeToFormatter(obj, path, f);
        }

        public static T DeserializeFromFormatter<T, F>(string path) where F : IFormatter, new()
        {
            T t;
            IFormatter f = new F();
            using (FileStream fs = File.OpenRead(path))
            {
                t = (T)f.Deserialize(fs);
            }
            return t;
        }

        public static void SerializeToXML<T>(string path, object obj)
        {
            XmlSerializer xs = new XmlSerializer(typeof(T));
            using (FileStream fs = File.Create(path))
            {
                xs.Serialize(fs, obj);
            }
        }

        public static T DeserializeFromXML<T>(string path)
        {
            XmlSerializer xs = new XmlSerializer(typeof(T));
            using (FileStream fs = File.OpenRead(path))
            {
                return (T)xs.Deserialize(fs);
            }
        }

        public static T DeserializeFromXml<T>(string xml)
        {
            T result;

            var ser = new XmlSerializer(typeof(T));
            using (var tr = new StringReader(xml))
            {
                result = (T)ser.Deserialize(tr);
            }
            return result;
        }


        private static void SerializeToFormatter(object obj, string path, IFormatter formatter)
        {
            using (FileStream fs = File.Create(path))
            {
                formatter.Serialize(fs, obj);
            }
        }
    }
}
[XmlRoot("PersonenListe")]
[XmlInclude(typeof(Person))] // include type class Person
public class PersonalList
{
    [XmlArray("PersonenArray")]
    [XmlArrayItem("PersonObjekt")]
    public List<Person> Persons = new List<Person>();

    [XmlElement("Listname")]
    public string Listname { get; set; }

    // Konstruktoren 
    public PersonalList() { }

    public PersonalList(string name)
    {
        this.Listname = name;
    }

    public void AddPerson(Person person)
    {
        Persons.Add(person);
    }
}
[XmlType("Person")] // define Type
[XmlInclude(typeof(SpecialPerson)), XmlInclude(typeof(SuperPerson))]  
        // include type class SpecialPerson and class SuperPerson
public class Person
{
    [XmlAttribute("PersID", DataType = "string")]
    public string ID { get; set; }

    [XmlElement("Name")]
    public string Name { get; set; }

    [XmlElement("City")]
    public string City { get; set; }

    [XmlElement("Age")]
    public int Age { get; set; }

    // Konstruktoren 
    public Person() { }

    public Person(string name, string city, int age, string id)
    {
        this.Name = name;
        this.City = city;
        this.Age = age;
        this.ID = id;
    }
}
[XmlType("SpecialPerson")] // define Type
public class SpecialPerson : Person
{
    [XmlElement("SpecialInterests")]
    public string Interests { get; set; }

    public SpecialPerson() { }

    public SpecialPerson(string name, string city, int age, string id, string interests)
    {
        this.Name = name;
        this.City = city;
        this.Age = age;
        this.ID = id;
        this.Interests = interests;
    }
}
[XmlType("SuperPerson")] // define Type
public class SuperPerson : Person
{
    [XmlArray("Skills")]
    [XmlArrayItem("Skill")]
    public List<String> Skills { get; set; }

    [XmlElement("Alias")]
    public string Alias { get; set; }

    public SuperPerson() 
    {
        Skills = new List<String>();
    }

    public SuperPerson(string name, string city, int age, string id, string[] skills, string alias)
    {
        Skills = new List<String>();

        this.Name = name;
        this.City = city;
        this.Age = age;
        this.ID = id;
        foreach (string item in skills)
        {
            this.Skills.Add(item);   
        }
        this.Alias = alias;
    }
}
static void Main(string[] args)
{
    PersonalList personen = new PersonalList(); 
    personen.Listname = "Friends";

    // normal person
    Person normPerson = new Person();
    normPerson.ID = "0";
    normPerson.Name = "Max Man";
    normPerson.City = "Capitol City";
    normPerson.Age = 33;

    // special person
    SpecialPerson specPerson = new SpecialPerson();
    specPerson.ID = "1";
    specPerson.Name = "Albert Einstein";
    specPerson.City = "Ulm";
    specPerson.Age = 36;
    specPerson.Interests = "Physics";

    // super person
    SuperPerson supPerson = new SuperPerson();
    supPerson.ID = "2";
    supPerson.Name = "Superman";
    supPerson.Alias = "Clark Kent";
    supPerson.City = "Metropolis";
    supPerson.Age = int.MaxValue;
    supPerson.Skills.Add("fly");
    supPerson.Skills.Add("strong");

    // Add Persons
    personen.AddPerson(normPerson);
    personen.AddPerson(specPerson);
    personen.AddPerson(supPerson);

    // Serialize 
    Type[] personTypes = { typeof(Person), typeof(SpecialPerson), typeof(SuperPerson) };
    XmlSerializer serializer = new XmlSerializer(typeof(PersonalList), personTypes); 
    FileStream fs = new FileStream("Personenliste.xml", FileMode.Create); 
    serializer.Serialize(fs, personen); 
    fs.Close(); 
    personen = null;

    // Deserialize 
    fs = new FileStream("Personenliste.xml", FileMode.Open); 
    personen = (PersonalList)serializer.Deserialize(fs); 
    serializer.Serialize(Console.Out, personen);
    Console.ReadLine();
}
private static void WriteObject(
        string fileName, IEnumerable<Vehichle> reflectedInstances, List<Type> knownTypeList)
    {
        using (FileStream writer = new FileStream(fileName, FileMode.Append))
        {
            foreach (var item in reflectedInstances)
            {
                var serializer = new DataContractSerializer(typeof(Vehichle), knownTypeList);
                serializer.WriteObject(writer, item);
            }
        }
    }
[System.Xml.Serialization.XmlArray] //This is the part that makes it work
List<object> serializableList = new List<object>();

XmlSerializer xmlSerializer = new XmlSerializer(serializableList.GetType());

serializableList.Add(PersonList);

using (StreamWriter streamWriter = System.IO.File.CreateText(fileName))
{
    xmlSerializer.Serialize(streamWriter, serializableList);
}