【问题标题】:Is it possible to deserialize XML into List<T>?是否可以将 XML 反序列化为 List<T>?
【发布时间】:2010-10-11 02:56:09
【问题描述】:

给定以下 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>

还有以下类:

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

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

是否可以使用 XmlSerializer 将 xml 反序列化为 List&lt;User&gt; ?如果是这样,我需要使用什么类型的附加属性,或者我需要使用什么附加参数来构造XmlSerializer 实例?

数组 (User[]) 是可以接受的,如果不太可取的话。

【问题讨论】:

    标签: c# serialization xml-serialization xml-deserialization


    【解决方案1】:

    不确定 List 但数组肯定是可行的。一点点魔法让再次进入列表变得非常容易。

    public class UserHolder {
       [XmlElement("list")]
       public User[] Users { get; set; }
    
       [XmlIgnore]
       public List<User> UserList { get { return new List<User>(Users); } }
    }
    

    【讨论】:

    • 可以不用“holder”类吗?
    • @Daniel,AFAIK,没有。您需要序列化和反序列化为一些具体的对象类型。我不相信 XML 序列化本身支持集合类作为序列化的开始。不过,我不是 100% 知道这一点。
    • [XmlElement("list")] 应该是 [XmlArray("list")] 代替。这是反序列化在 .NET 4.5 中为我工作的唯一方法
    【解决方案2】:

    是的,它会序列化和反序列化一个 List。如有疑问,请确保使用 [XmlArray] 属性。

    [Serializable]
    public class A
    {
        [XmlArray]
        public List<string> strings;
    }
    

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

    【讨论】:

      【解决方案3】:

      您可以简单地封装列表:

      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);
          }
      }
      

      【讨论】:

      • 使用 [XmlElement("user")] 的很好的解决方案可以避免额外级别的元素。看着这个,我确信它会发出一个 节点(如果您没有 XmlElement 属性),然后在其下添加 节点。但我试过了,但没有,因此发出了问题想要的内容。
      • 如果我在上面的 UserList 下有两个列表怎么办?我试过你的方法,它说它已经定义了一个名为 XYZ 的成员,具有相同的参数类型
      • 我不知道为什么这被标记为正确答案。它包括添加一个类来包装列表。这当然是问题试图避免的。
      • @DDRider62 问题没有说“没有包装”。大多数人都很务实,只想把数据拿出来。此答案允许您通过 .Items 成员执行此操作。
      【解决方案4】:

      是的,它确实反序列化为 List。无需将其保存在数组中并将其包装/封装在列表中。

      public class UserHolder
      {
          private List<User> users = null;
      
          public UserHolder()
          {
          }
      
          [XmlElement("user")]
          public List<User> Users
          {
              get { return users; }
              set { users = value; }
          }
      }
      

      反序列化代码,

      XmlSerializer xs = new XmlSerializer(typeof(UserHolder));
      UserHolder uh = (UserHolder)xs.Deserialize(new StringReader(str));
      

      【讨论】:

        【解决方案5】:

        我想我找到了更好的方法。您不必将属性放入您的类中。我做了两种以泛型列表为参数的序列化和反序列化方法。

        看看(对我有用):

        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;
            }
        

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

                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);
        

        【讨论】:

        • 感谢您实际回答问题。我要补充一点,对于List&lt;MyClass&gt;,文档元素应命名为ArrayOfMyClass
        【解决方案6】:

        怎么样

        XmlSerializer xs = new XmlSerializer(typeof(user[]));
        using (Stream ins = File.Open(@"c:\some.xml", FileMode.Open))
        foreach (user o in (user[])xs.Deserialize(ins))
           userList.Add(o);    
        

        不是特别花哨,但应该可以。

        【讨论】:

        • 欢迎来到stackoverflow!最好为示例代码提供简短描述以提高发布准确性:)
        【解决方案7】:

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

        [XmlType("user")]
        public class User
        {
           ...
        }
        

        然后XmlSerializer ctor 上的XmlRootAttribute 可以提供所需的根并允许直接读入 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);
            }
        

        ...

            // 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);
            }
        

        信用:基于来自YK1answer

        【讨论】:

        • 在我看来,这显然是问题的答案。问题是关于反序列化为 List。所有其他解决方案,可能除了一个之外,都包含一个包含列表的包装类,这当然不是发布的问题,以及问题的作者似乎试图避免的问题。
        • 使用这种方法,XmlSerializer 必须被静态缓存和重用以避免严重的内存泄漏,详情请参阅Memory Leak using StreamReader and XmlSerializer
        猜你喜欢
        • 2011-09-28
        • 2018-10-30
        • 2011-01-06
        • 2012-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多