使用反射将 XML 数组反序列化为列表

问题描述

我想将一个 XML 文档反序列化为一个对象,这是我的对象定义:

public class Student
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<string> Hobbies { get; set; }
}

这是 XML 文件,节点名称匹配类属性

<?xml version="1.0" encoding="UTF-8"?>
<items>
    <item type="dict">
        <FirstName type="str">John</FirstName>
        <LastName type="str">Smith</LastName>
        <Hobbies type="list">
            <item type="str">Reading</item>
            <item type="str">Singing</item>
            <item type="str">Tennis</item>
        </Hobbies>
    </item>
</items>

以下代码曾经起作用,我将 XML 节点(在本例中为 item)传递给函数代码将使用反射将属性与子节点匹配并设置属性值:

public void DeserializeNode(XmlNode node)
{
    var student = new Student();

    foreach (XmlNode child in node)
    {
        PropertyInfo prop = student.GetType().GetProperty(child.Name);
        prop.SetValue(student,child.InnerText);
    }
}

但是上面的函数不再起作用(XML 输入已更改,现在它有一个名为 hobbies 的数组)

以下行抛出异常:

prop.SetValue(student,child.InnerText); // child.InnerText = ReadingSingingTennis

这是因为爱好的 child.InnerText 返回 ReadingSingingTennis 并且代码尝试将 List<string> tp 设置为单个 string

如何修改功能以正确设置爱好?

解决方法

问题是在 Hobbies 中你有节点。

所以你可以试试这个。

 public static void DeserializeNode(XmlNode node)
    {
        var student = new Student();

        foreach (XmlNode child in node)
        {
            PropertyInfo prop = student.GetType().GetProperty(child.Name);
            if (child.Attributes.GetNamedItem("type").Value == "list")
            {
                var list = Activator.CreateInstance(prop.PropertyType);
                foreach (XmlNode item in child)
                {
                    var methodInfo = list.GetType().GetMethod("Add");
                    methodInfo.Invoke(list,new object[] { item.InnerText });
                }

                prop.SetValue(student,list);
            }
            else
            {
                prop.SetValue(student,child.InnerText);
            }
        }
    }

但是如果你有更复杂的 xml 你应该使用递归和反射