是否可以将XML反序列化为List <T>?

Dan*_*fer 147 c# serialization xml-serialization xml-deserialization

给出以下XML:

<?xml version="1.0"?>
<user_list>
   <user>
      <id>1</id>
      <name>Joe</name>
   </user>
   <user>
      <id>2</id>
      <name>John</name>
   </user>
</user_list>
Run Code Online (Sandbox Code Playgroud)

以下课程:

public class User {
   [XmlElement("id")]
   public Int32 Id { get; set; }

   [XmlElement("name")]
   public String Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

是否可以使用XmlSerializer将xml反序列化为List<User>?如果是这样,我需要使用哪种类型的附加属性,或者我需要使用哪些其他参数来构造XmlSerializer实例?

User[]如果有点不太可取的话,array()是可以接受的.

Mar*_*ell 130

您可以简单地封装列表:

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

[XmlRoot("user_list")]
public class UserList
{
    public UserList() {Items = new List<User>();}
    [XmlElement("user")]
    public List<User> Items {get;set;}
}
public class User
{
    [XmlElement("id")]
    public Int32 Id { get; set; }

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

static class Program
{
    static void Main()
    {
        XmlSerializer ser= new XmlSerializer(typeof(UserList));
        UserList list = new UserList();
        list.Items.Add(new User { Id = 1, Name = "abc"});
        list.Items.Add(new User { Id = 2, Name = "def"});
        list.Items.Add(new User { Id = 3, Name = "ghi"});
        ser.Serialize(Console.Out, list);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 使用[XmlElement("user")]的好解决方案,以避免额外的元素级别.看看这个,我确信它会发出一个<user>或<Items>节点(如果你没有XmlElement属性),然后在其下添加<user>节点.但我尝试了它并没有,因此完全解决了问题所需. (5认同)
  • 我不知道为什么这被标记为正确答案。它包括添加一个类来包装列表。这当然是问题试图避免的。 (2认同)

ric*_*aux 46

如果您User使用XmlType匹配所需大写的类来装饰类:

[XmlType("user")]
public class User
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

然后XmlRootAttributeXmlSerializerctor上可以提供所需的根并允许直接读入List <>:

    // e.g. my test to create a file
    using (var writer = new FileStream("users.xml", FileMode.Create))
    {
        XmlSerializer ser = new XmlSerializer(typeof(List<User>),  
            new XmlRootAttribute("user_list"));
        List<User> list = new List<User>();
        list.Add(new User { Id = 1, Name = "Joe" });
        list.Add(new User { Id = 2, Name = "John" });
        list.Add(new User { Id = 3, Name = "June" });
        ser.Serialize(writer, list);
    }
Run Code Online (Sandbox Code Playgroud)

...

    // read file
    List<User> users;
    using (var reader = new StreamReader("users.xml"))
    {
        XmlSerializer deserializer = new XmlSerializer(typeof(List<User>),  
            new XmlRootAttribute("user_list"));
        users = (List<User>)deserializer.Deserialize(reader);
    }
Run Code Online (Sandbox Code Playgroud)

信用:基于答案来自YK1.

  • 在我看来,这显然是问题的答案.问题是关于反序列化到List <T>.所有其他解决方案,除了一个,包括一个包含类,包含列表,这当然不是发布的问题,以及问题的作者似乎试图避免. (10认同)
  • 使用这种方法,`XmlSerializer` 必须静态缓存和重用以避免严重的内存泄漏,详细信息请参见 [使用 StreamReader 和 XmlSerializer 的内存泄漏](/sf/ask/1672800181/)。 (2认同)

Coi*_*oin 16

是的,它将序列化和反序列化List <>.如果有疑问,请确保使用[XmlArray]属性.

[Serializable]
public class A
{
    [XmlArray]
    public List<string> strings;
}
Run Code Online (Sandbox Code Playgroud)

这适用于Serialize()和Deserialize().


tud*_*scu 16

我想我找到了一个更好的方法.您不必将属性放入类中.我已经为序列化和反序列化制作了两种方法,它们将通用列表作为参数.

看一下(它对我有用):

private void SerializeParams<T>(XDocument doc, List<T> paramList)
    {
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(paramList.GetType());

        System.Xml.XmlWriter writer = doc.CreateWriter();

        serializer.Serialize(writer, paramList);

        writer.Close();           
    }

private List<T> DeserializeParams<T>(XDocument doc)
    {
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<T>));

        System.Xml.XmlReader reader = doc.CreateReader();

        List<T> result = (List<T>)serializer.Deserialize(reader);
        reader.Close();

        return result;
    }
Run Code Online (Sandbox Code Playgroud)

所以你可以序列化你想要的任何列表!您不需要每次都指定列表类型.

        List<AssemblyBO> list = new List<AssemblyBO>();
        list.Add(new AssemblyBO());
        list.Add(new AssemblyBO() { DisplayName = "Try", Identifier = "243242" });
        XDocument doc = new XDocument();
        SerializeParams<T>(doc, list);
        List<AssemblyBO> newList = DeserializeParams<AssemblyBO>(doc);
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你真的回答了这个问题.我想补充一点,对于`List <MyClass>`,文档元素应命名为`ArrayOfMyClass`. (3认同)

Nem*_*emo 7

是的,它确实反序列化为List <>.无需将其保留在数组中并将其打包/封装在列表中.

public class UserHolder
{
    private List<User> users = null;

    public UserHolder()
    {
    }

    [XmlElement("user")]
    public List<User> Users
    {
        get { return users; }
        set { users = value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

反序列化代码,

XmlSerializer xs = new XmlSerializer(typeof(UserHolder));
UserHolder uh = (UserHolder)xs.Deserialize(new StringReader(str));
Run Code Online (Sandbox Code Playgroud)


Jar*_*Par 5

不确定List <T>,但是数组肯定是可行的。一点点魔术使重新进入列表变得非常容易。

public class UserHolder {
   [XmlElement("list")]
   public User[] Users { get; set; }

   [XmlIgnore]
   public List<User> UserList { get { return new List<User>(Users); } }
}
Run Code Online (Sandbox Code Playgroud)

  • 没有“ holder”类,是否可以做? (2认同)