【问题标题】:Property's derived class is discarded(i.e., replaced with the base class) upon XML deserialization属性的派生类在 XML 反序列化时被丢弃(即,替换为基类)
【发布时间】:2014-07-10 15:45:06
【问题描述】:

我有一个如下所示的游戏数据类:

public class SaveGameData  {

    public virtual List<PropertyContainer> properties {get; set; }

}  

还有这些类:

public class PropertyContainer {

    public Property property {get; set; }//Could be set to DerivedProperty

}
public class Property {
    public int BasePropertyData {get; set;}
}
public class DerivedProperty : Property {
    public int DerivedPropertyData {get; set; }    
}

我正在尝试在播放会话之间保存/加载这些数据,我正在为此过程使用 XML 序列化/反序列化。

问题在于,在 PropertyContainer 类中,派生的属性有时会被用来替代 Property 类,如下所示:

PropertyContainer container = new PropertyContainer();
container.property = derivedProperty; 

当容器被序列化时,派生类及其特殊属性也被保存了,这里没问题。

序列化代码如下:

serializer = new System.Xml.Serialization.XmlSerializer(typeof(SaveGameData));

SaveGameData dataToSave = GetSaveGameData();
using (var stream = new StringWriter()) {
serializer.Serialize(stream, dataToSave); 
...write to file... 

 }

序列化过程似乎正在工作,因为派生类被正确识别并保存到 XML 文件中,XML 输出如下所示:

<?xml version="1.0" encoding="utf-16"?>
<SaveGameData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <properties>

    <PropertyContainer>

      <property xsi:type="DerivedProperty">

      <BasePropertyData>1</BasePropertyData>
      <DerivedPropertyData>1</DerivedPropertyData>

      </property>

    </PropertyContainer>

  </properties>

</SaveGameData>  

但是当 XML 文件被反序列化时,所有的派生类都会被丢弃。下面是反序列化代码:

SaveGameData result;
string data = ReadSaveGameData();
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(SaveGameData));

        using (StringReader stream = new StringReader(savedGame)) {
            result = (SaveGameData)serializer.Deserialize(stream);

        }  

这意味着在加载 XML 数据后,在派生属性上调用 GetType()(例如 saveGameData.properties[0].GetType(),假设属性是 DerivedProperty)将生成基类,即 Property;通过扩展,它丢弃了所有 DerivedProperty 的属性。有问题。

附注: 我尝试添加XmlInclude 属性,但没有任何改变:

[System.Xml.Serialization.XmlInclude(typeof(DerivedProperty))]
public class Property {

...

}  

我该如何解决这个问题?我的方法是否有可行的替代方案?

【问题讨论】:

    标签: c# xml serialization deserialization xml-deserialization


    【解决方案1】:

    一种选择是切换到DataContractSerializer。然后使用KnownTypeAttribute 标识子类。

    public class PropertyContainer {
    
        public Property property {get; set; }//Could be set to DerivedProperty
    
    }
    [KnownType(typeof(DerivedProperty))]
    public class Property {
        public int BasePropertyData {get; set;}
    }
    public class DerivedProperty : Property {
        public int DerivedPropertyData {get; set; }    
    }
    

    【讨论】:

      【解决方案2】:

      [XmlInclude(typeof(DerivedProperty))] 装饰Property 类应该可以工作。事实上,没有它,XmlSerializer 甚至不会让你首先序列化 DerivedProperty

      以下程序是基于您的代码的工作示例。请确认您的机器上的控制台输出也是True。如果是,您将需要确定该代码与您最初的尝试有何不同。然后更新您的问题,以便我们深入挖掘。

      using System;
      using System.Collections.Generic;
      using System.IO;
      using System.Xml.Serialization;
      
      class Program
      {
          static void Main()
          {
              string savedGame = @"
      <SaveGameData xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
        <properties>
          <PropertyContainer>
            <property xsi:type='DerivedProperty'>
              <BasePropertyData>1</BasePropertyData>
              <DerivedPropertyData>1</DerivedPropertyData>
            </property>
          </PropertyContainer>
        </properties>
      </SaveGameData>";
              XmlSerializer serializer = new XmlSerializer(typeof(SaveGameData));
              SaveGameData result;
      
              using (StringReader stream = new StringReader(savedGame))
              {
                  result = (SaveGameData)serializer.Deserialize(stream);
              }
      
              Console.WriteLine(result.properties[0].property is DerivedProperty); // True
          }
      }
      
      public class SaveGameData
      {
          public virtual List<PropertyContainer> properties { get; set; }
      }
      
      public class PropertyContainer
      {
          public Property property { get; set; }//Could be set to DerivedProperty
      }
      
      [XmlInclude(typeof(DerivedProperty))]
      public class Property
      {
          public int BasePropertyData { get; set; }
      }
      
      public class DerivedProperty : Property
      {
          public int DerivedPropertyData { get; set; }
      }
      

      【讨论】:

      • 我不完全确定这个不存在的错误是如何通过我的,但它确实浪费了我的时间。感谢您指出这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多