【问题标题】:Problems deserializing List of objects反序列化对象列表的问题
【发布时间】:2013-08-21 20:35:27
【问题描述】:

我在反序列化对象列表时遇到问题。我只能将一个对象序列化为一个对象,但无法获取列表。我没有收到任何错误,它只是返回一个空列表。这是返回的 XML:

<locations>
   <location locationtype="building" locationtypeid="1">
     <id>1</id>
     <name>Building Name</name>
     <description>Description of Building</description>
   </location>
</locations>

这是我拥有的类,我在 GetAll 方法中反序列化:

[Serializable()]
[XmlRoot("location")]
public class Building
{
    private string method;

    [XmlElement("id")]
    public int LocationID { get; set; }
    [XmlElement("name")]
    public string Name { get; set; }
    [XmlElement("description")]
    public string Description { get; set; }
    [XmlElement("mubuildingid")]
    public string MUBuildingID { get; set; }

    public List<Building> GetAll()
    {
        var listBuildings = new List<Building>();
        var building = new Building();
        var request = WebRequest.Create(method) as HttpWebRequest;
        var response = request.GetResponse() as HttpWebResponse;

        var streamReader = new StreamReader(response.GetResponseStream());
        TextReader reader = streamReader;
        var serializer = new XmlSerializer(typeof(List<Building>), 
            new XmlRootAttribute() { ElementName = "locations" });
        listBuildings = (List<Building>)serializer.Deserialize(reader);

        return listBuildings;
    }
}

【问题讨论】:

  • 你遇到了什么错误?
  • 哪些列表没有看到序列化?如果是GetAll() 方法,那是因为序列化程序(好吧,可能很少,我猜)不在调用类方法的业务中。他们的职责是保留对象的属性值。
  • 我没有收到错误,它只是返回一个空列表。我不是在尝试序列化 GetAll 方法,而是使用 Get All 方法从 Web 服务反序列化并填充该构建对象。

标签: c# xml serialization


【解决方案1】:

试试这个:

[XmlRoot("locations")]
public class BuildingList
{
    public BuildingList() {Items = new List<Building>();}
    [XmlElement("location")]
    public List<Building> Items {get;set;}
}

然后反序列化整个 BuildingList 对象。

var xmlSerializer = new XmlSerializer(typeof(BuildingList));
var list = (BuildingList)xmlSerializer.Deserialize(xml);

【讨论】:

  • 仅供参考,如果您需要反序列化属性(例如 locationtype 等),也可以通过使用 XmlAttribute 装饰相应的属性来实现。
  • 错误 4 属性“XmlElement”在此声明类型上无效。它仅对“属性、索引器、字段、参数、返回”声明有效。
  • 这对你有用吗?我测试了代码,它能够正确反序列化几个位置的列表。您只需返回 list.Items 即可获得 List&lt;Locations&gt;
【解决方案2】:

我知道这是一个老问题,但我今天为此苦苦挣扎,找到了一个不需要封装的答案。

假设 1:您可以控制源 Xml 及其构建方式。

假设 2:您正在尝试将 Xml 直接序列化为 List&lt;T&gt; 对象

  1. 您必须将 Xml 中的 Root 元素命名为 ArrayOfxxx,其中 xxx 是您的类的名称(或在 XmlType 中指定的名称(参见 2.))
  2. 如果您希望您的 xml 元素具有与类不同的名称,您应该在类上使用 XmlType

注意:如果您的类型名称(或类名称)以小写字母开头,则应将第一个字符转换为大写。

示例 1 - 没有 XmlType

class Program
{
    static void Main(string[] args)
    {
        //String containing the xml array of items.
        string xml =
@"<ArrayOfItem>
    <Item>
        <Name>John Doe</Name>
    </Item>
    <Item>
        <Name>Martha Stewart</Name>
    </Item>
</ArrayOfItem>";


        List<Item> items = null;
        using (var mem = new MemoryStream(Encoding.Default.GetBytes(xml)))
        using (var stream = new StreamReader(mem))
        {
            var ser = new XmlSerializer(typeof(List<Item>)); //Deserialising to List<Item>
            items = (List<Item>)ser.Deserialize(stream);
        }

        if (items != null)
        {
            items.ForEach(I => Console.WriteLine(I.Name));
        }
        else
            Console.WriteLine("No Items Deserialised");

    }
}

public class Item
{
    public string Name { get; set; }
}

示例 2 - 使用 XmlType

class Program
{
    static void Main(string[] args)
    {
        //String containing the xml array of items.
        //Note the Array Name, and the Title case on stq.
        string xml =
@"<ArrayOfStq>
    <stq>
        <Name>John Doe</Name>
    </stq>
    <stq>
        <Name>Martha Stewart</Name>
    </stq>
</ArrayOfStq>";


        List<Item> items = null;
        using (var mem = new MemoryStream(Encoding.Default.GetBytes(xml)))
        using (var stream = new StreamReader(mem))
        {
            var ser = new XmlSerializer(typeof(List<Item>)); //Deserialising to List<Item>
            items = (List<Item>)ser.Deserialize(stream);
        }

        if (items != null)
        {
            items.ForEach(I => Console.WriteLine(I.Name));
        }
        else
            Console.WriteLine("No Items Deserialised");

    }
}

[XmlType("stq")]
public class Item
{
    public string Name { get; set; }
}

【讨论】:

    【解决方案3】:

    不确定 Building 如何与您在 xml 中的位置相对应,但对我来说,如果它们的名称相同,则更有意义。而不是使用 List 使用 LocationList,它变成:

    [Serializable()]
    [XmlRoot("locations")]
    public class LocationCollection{
        [XmlElement("location")]
        public Location[] Locations {get;set;}
    }
    
    [Serializable()]
    [XmlRoot("location")]
    public class Location
    {    
        [XmlElement("id")]
        public int LocationID { get; set; }
        [XmlAttribute("locationtype")]
        public string LocationType {get;set;}
        [XmlElement("name")]
        public string Name { get; set; }
        [XmlElement("description")]
        public string Description { get; set; }
        [XmlElement("mubuildingid")]
        public string MUBuildingID { get; set; }    
    }
    

    然后您可以按如下方式反序列化:

    var request = WebRequest.Create(method) as HttpWebRequest;
    var response = request.GetResponse() as HttpWebResponse;
    
    var streamReader = new StreamReader(response.GetResponseStream());
    TextReader reader = streamReader;
    var serializer = new XmlSerializer(typeof(LocationCollection), 
       new XmlRootAttribute() { ElementName = "locations" });
    var listBuildings = (LocationCollection)serializer.Deserialize(reader);
    
    return listBuildings;
    

    【讨论】:

    • 建筑物只是 LocationType 的一种类型,而这个特定的应用程序只需要建筑物,因此它有一个正在使用的建筑物对象,它将通过 Web 服务填充到应用程序中。我试图避免仅为 Collections 创建另一个类,因为在方法或对象内部的静态方法中返回它会使所有内容都本地化在对象中。
    • 恕我直言,在内部调用 Web 服务的 DTO 对我来说似乎是一个非常糟糕的主意。此外,您仍然可以将 LocationCollection 保留在内部,然后只返回 listBuildings.Locations,即 Location[]
    • 这与我发布的内容有何不同?您仅从 List 切换到数组,并且 OP 请求了 List
    • 这个答案的数组部分对我有帮助,因为我使用的 javascript 反序列化器无法创建列表
    【解决方案4】:

    我知道,老问题,但在遇到类似问题时遇到了它。 基于@ricovox 的回答和 OP 的问题,这是我用来序列化他的 xml 的模型:

    [Serializable, XmlRoot("locations")]
    public class BuildingList
    {
        [XmlArrayItem("location", typeof(Building))]
        public List<Building> locations { get; set; }
    }
    
    [Serializable]
    public class Building
    {
        public int LocationID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public string MUBuildingID { get; set; }
    
        public List<Building> GetAll()
        {
            ...
        }
    }
    

    OP 的错误是将列表项创建为根

    【讨论】:

      【解决方案5】:

      将 [XMLArray] 用于集合属性。

      【讨论】:

        猜你喜欢
        • 2013-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-04
        • 1970-01-01
        • 1970-01-01
        • 2022-01-25
        相关资源
        最近更新 更多