【问题标题】:How to serialize/deserialize a class with a generic property?如何序列化/反序列化具有泛型属性的类?
【发布时间】:2025-12-11 01:10:01
【问题描述】:

我无法反序列化包含通用属性 T 的类。我得到的例外是:

无法生成临时类(结果=1)。错误 CS0030:不能 将类型“教师”转换为“程序员”错误 CS0029:无法将类型“程序员”隐式转换为 “老师”

我的类结构的一个人为示例是:

[Serializable]
public class Person<T> where T : Profession
{
    [XmlElement("Teacher", typeof(Teacher))]
    [XmlElement("Programmer", typeof(Programmer))]
    public T Profession { get; set; }
}

[Serializable]
[XmlInclude(typeof(Teacher))] // A Subclass
[XmlInclude(typeof(Programmer))] // A Subclass
public class Profession
{}

[Serializable]
public class Teacher : Profession
{
    [XmlElement]
    public int Salary { get; set; }
}


[Serializable]
public class Programmer : Profession
{
    [XmlElement]
    public long MassiveSalary { get; set; }
}

我要反序列化的XML文件的结构是:

<Person>
    <Programmer/>
</Person>

或者可能是……

<Person>
    <Teacher />
</Person>

here 描述了基本上相同的问题,但使用的解决方案/解决方法对我来说没有意义。在这种情况下,解决方法是定义不同类型之间的隐式转换(本例中为教师/程序员)。

最后一点是,如果我注释掉其中一个职业,那么我可以反序列化至少一个版本的文件。例如:

[Serializable]
public class Person<T> where T : Profession
{
    // Comment out 'Programmer' and I can deserialise all files with a 'Teacher' XMLElement
    [XmlElement("Teacher", typeof(Teacher))]
    //[XmlElement("Programmer", typeof(Programmer))]

    public T Profession { get; set; }
}

然后就可以反序列化文件了。谁能解释是否可以这样做,或提出合理的解决方法?谢谢。

【问题讨论】:

  • 你能改变XML格式吗?还是固定的?
  • 哦,您是否提前知道您是在反序列化 Person&lt;Teacher&gt; 还是 Person&lt;Programmer&gt;,还是需要在反序列化期间确定?
  • 我可以稍微改变一下格式——你有什么建议?我会提前知道我想反序列化什么类型。
  • 如果你事先知道,为什么要更改元素名称呢?对于所有泛型类型,将其保留为 &lt;Person&gt;&lt;Profession /&gt;&lt;/Person&gt;
  • 每个职业的根元素名称不可修改。因此,XML 文档必须包含“”或“”标签,而不是 标签。我曾考虑放弃通用属性,而是在我的“人”类中持有“职业”。然后我可以反序列化任何职业并转换为更具体的类型。例如: [XmlElement("Teacher", typeof(Teacher))] [XmlElement("Programmer", typeof(Programmer))] public Profession Profession { get;放; }。这可以正常工作,但使用通用 T 会更好。

标签: c# xml generics xml-serialization


【解决方案1】:

尝试以下 xml linq :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq; 

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml =
                "<Root>" +
                   "<Person>" +
                      "<Programmer/>" +
                      "<Teacher/>" +
                   "</Person>" +
                "</Root>";

            XElement root = XElement.Parse(xml);

            string[] persons = root.Descendants("Person").Elements().Select(x => x.Name.LocalName).ToArray();
        }
    }
}

【讨论】: