【问题标题】:Xml being deserialized into base class instead of derived classesXml 被反序列化为基类而不是派生类
【发布时间】:2015-08-21 11:43:55
【问题描述】:

我知道这是一个热门话题,我进行了广泛的研究,但没有找到问题的答案。

我有一个基类IntroductionAction 和两个派生类IntroductionActionComplexIntroductionActionSimple。我有一个IntroductionAction 对象列表,我已向其中添加了两种派生类型的对象。我的课程如下:

[XmlInclude(typeof(IntroductionActionComplex))]
[XmlInclude(typeof(IntroductionActionSimple))]
public class IntroductionAction
{
    public IntroductionAction() { }
}

public class IntroductionActionComplex : IntroductionAction
{
    [XmlIgnore]
    public string name { get; set; }

    [XmlElement(ElementName = "QuestionString")]
    public string question { get; set; }

    [XmlElement(ElementName = "AnswerString")]
    public List<string> answerStrings { get; set; }

    public IntroductionActionComplex()
    {
        name = string.Empty;
        question = null;
        answerStrings = new List<string>();
    }
}

public class IntroductionActionSimple : IntroductionAction
{
    [XmlIgnore]
    public string name { get; set; }

    [XmlText]
    public string Value { get; set; }

    public IntroductionActionSimple()
    {
        Value = string.Empty;
    }
}

然后我按如下方式创建列表

[XmlElement("IntroductionAction")]
public List<IntroductionAction> introductionActions { get; set; }

我正在使用XmlSerializer 并且所有内容都正确序列化。这是包含正确派生类之一的列表的结果 XML。

<IntroductionAction>
  <QuestionString>
    test
  </QuestionString>
  <AnswerString>
    test
  </AnswerString>
  <AnswerString>
    test
  </AnswerString>
</IntroductionAction>
<IntroductionAction>
  test
</IntroductionAction>

此 XML 文件将进入设备,该设备不会将其读取为 XML,而只是搜索标签并执行它需要做的任何工作,因此该文件不能包含任何 XSI 或 XSD 标签,缩进等通常与适当的 XML 相关联。

我的反序列化代码很简单:

public static T Deserialize_xml_Config<T>(string file1, T obj)
{
   XmlSerializer deserializer = new XmlSerializer(obj.GetType());
   using (TextReader reader = new StreamReader(file1))
   {
      return (T)deserializer.Deserialize(reader);
   }
}

最后是我的问题。当我反序列化时,它被反序列化为基类IntroductionAction,而不是派生类。 这些IntroductionAction 类只是我正在序列化/反序列化的更大对象的一部分。我尝试将基类抽象化,因为它不包含任何功能,但是在反序列化时出现错误提示

指定的类型是抽象的:name='IntroductionAction'

尽管我的 XmlIncludes 似乎无法找到派生类。

我尝试将类型添加到序列化程序,但没有奏效。

非常感谢任何帮助。

编辑: 这就是我将类型添加到序列化程序的意思

XmlSerializer deserializer = new XmlSerializer(obj.GetType(), new Type [] { typeof(IntroductionActionComplex), typeof(IntroductionActionSimple) });
using (TextReader reader = new StreamReader(file1))
{
   return (T)deserializer.Deserialize(reader);
}

我也尝试使用XmlAttributeOverrides

XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
var attrs = new XmlAttributes();
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "IntroductionAction";
attr.Type = typeof(IntroductionActionComplex);
attrs.XmlElements.Add(attr);
attr.ElementName = "IntroductionAction";
attr.Type = typeof(IntroductionActionSimple);
attrs.XmlElements.Add(attr);
attrOverrides.Add(typeof(IntroductionAction), "IntroductionAction", attrs);

XmlSerializer deserializer = new XmlSerializer(obj.GetType(), attrOverrides);
using (TextReader reader = new StreamReader(file1))
{
   return (T)deserializer.Deserialize(reader);
}

【问题讨论】:

  • 在每个类上方添加一个 [XmlRoot(ElementName = "......")] 与实际标签名称(区分大小写)以指定您想要每个标签的类进入。
  • 你能发布你为I have tried adding the types to the serializer but that didnt work所做的事情吗?我相信你需要覆盖 xml 属性,但我想看看你先做了什么。
  • @jdweng 很确定这不会起作用,因为两个派生对象必须使用相同的标签名称,即
  • 您的 XML 没有正确生成——每个 &lt;IntroductionAction&gt; 元素上应该有一个 xsi:type 属性来指定类型,例如&lt;IntroductionAction xsi:type="IntroductionActionComplex"&gt;。您是如何生成 XML 的?如果我用XmlSerializer 序列化你的类,就会出现类型信息。
  • @dbc 我必须重写 TextWriter 以删除这些标签,因为它们不能出现在文件中。这超出了我的控制范围,这就是它必须的方式。我已经使用存在的那些类型标签对其进行了测试,并且一切正常,因此只有在删除它们时才会成为问题。

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


【解决方案1】:

我认为你很接近。下面是基于派生类类型保存和加载 XML 文件的完整示例。这会将节点保存为派生类型本身,因此重新加载将保留所需的类型,而不是转换回基本类型。您可能需要添加异常处理,这只是一个快速的解决方案。我没有更改您的基础 IntroductionAction 或派生的 IntroductionActionComplex / IntroductionActionSimple 类。

public class RootNode
{
   [XmlElement("IntroductionAction")]
   public List<IntroductionAction> introductionActions { get; set; }

   public RootNode()
   {
      introductionActions = new List<IntroductionAction>();
   }

   private static XmlAttributeOverrides GetXmlAttributeOverrides()
   {
      XmlAttributeOverrides xml_attr_overrides = new XmlAttributeOverrides();
      XmlAttributes xml_attrs = new XmlAttributes();
      xml_attrs.XmlElements.Add(new XmlElementAttribute(typeof(IntroductionActionComplex)));
      xml_attrs.XmlElements.Add(new XmlElementAttribute(typeof(IntroductionActionSimple)));
      xml_attr_overrides.Add(typeof(RootNode), "introductionActions", xml_attrs);
      return xml_attr_overrides;
   }

   // Add exception handling
   public static void SaveToFile(RootNode rootNode, string fileName)
   {
      using (MemoryStream mem_stream = new MemoryStream())
      {
         XmlSerializer serializer = new XmlSerializer(rootNode.GetType(), RootNode.GetXmlAttributeOverrides());
         serializer.Serialize(mem_stream, rootNode);

         using (BinaryWriter output = new BinaryWriter(new FileStream(fileName, FileMode.Create)))
         {
            output.Write(mem_stream.ToArray());
         }
      }
   }

   // Add exception handling
   public static RootNode LoadFromFile(string fileName)
   {
      if (File.Exists(fileName))
      {
         using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
         {
            using (TextReader reader = new StreamReader(file))
            {
               XmlSerializer serializer = new XmlSerializer(typeof(RootNode), RootNode.GetXmlAttributeOverrides());
               return (RootNode)serializer.Deserialize(reader);
            }
         }
      }
      return null;
   }
}

测试程序:

internal class Program
{
   private static void Main(string[] args)
   {
      RootNode obj = new RootNode();
      obj.introductionActions.Add(new IntroductionActionComplex() { question = "qTest", answerStrings = { "aTest1", "aTest2" }, name = "aName1" });
      obj.introductionActions.Add(new IntroductionActionSimple() { name = "aName2", Value = "aValue" });

      RootNode.SaveToFile(obj, "Test.xml");

      RootNode obj2 = RootNode.LoadFromFile("Test.xml");
   }
}

【讨论】:

  • 在上面的 GetXmlAttributeOverrides() 函数中,添加到 xml_attr_overrides 时有 typeof(RootNode)。那是指创建和初始化 IntroductionActions 列表的类吗?
  • @M.Geaney - 是的。如果您希望 XML 中的节点全部为 IntroductionAction 而不是派生类名称,您可以将其更改为 typeof(IntroductionAction) 并且 xml 将使用其类型标记每个节点。在我看来,XML 变得更加冗长且不太清晰,但它是另一种选择。
  • 我试了一下,但没有运气。它仍在反序列化为 2 个基类 IntroductionAction 对象,而不是 IntroductionActionComplex 和 IntroductionActionSimple 对象。
猜你喜欢
  • 2014-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-10
相关资源
最近更新 更多