反序列化对象列表时出现问题

6

我在反序列化对象列表时遇到了问题。我可以将一个对象序列化为对象,但无法获取列表。没有报错,它只返回一个空列表。这是返回的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;
    }
}

你遇到了什么错误? - Agustin Meriles
你没有看到序列化的列表是什么?如果是GetAll()方法,那是因为序列化程序不会(也许很少)调用类方法。它们的任务是保留对象的属性值。 - 48klocs
我没有收到错误信息,只是返回了一个空列表。我并不试图序列化GetAll方法,而是使用GetAll方法从Web服务反序列化并填充该建筑对象。 - Andy Xufuris
5个回答

6

试试这个:

[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进行装饰来实现。 - drwatsoncode
错误 4 属性 'XmlElement' 不适用于此声明类型。它只适用于 '属性、索引器、字段、参数、返回值' 声明。 - Andy Xufuris
这对你有用吗?我测试了代码,它能够正确反序列化多个位置的列表。你只需返回 list.Items 就可以得到 List<Locations> - drwatsoncode

3

我知道这是一个旧的问题,但今天我遇到了这个问题,并找到了一个不需要封装的答案。

假设1:您控制源Xml以及它如何构建。

假设2:您正在尝试将Xml直接序列化为List<T>对象

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

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

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

2

不确定“Building”与您在XML中拥有的位置相对应,但对我而言,如果它们被命名为等效项,则更有意义。请改用LocationList而不是List,即可变成:

[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服务填充。我试图避免为集合创建另一个类,因为在对象内部的方法或静态方法中返回它可以使所有内容都局限在对象内部。 - Andy Xufuris
1
在我看来,一个数据传输对象内部调用 Web 服务似乎是一个非常糟糕的想法。此外,您仍然可以将 LocationCollection 保持为内部状态,然后只返回 listBuildings.Locations,即 Location[]。 - DavidN
这与我发布的有何不同?你只是从List<T>切换到了数组,而OP请求的是List<T>。 - drwatsoncode
这个答案中的数组部分对我很有帮助,因为我使用的 JavaScript 反序列化程序无法创建列表。 - aaron

0

我知道这是一个老问题,但当我面临类似的问题时,我遇到了它。 在@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()
    {
        ...
    }
}

楼主的错误在于将列表项创建为根元素


-1
使用[XMLArray]来处理集合属性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接