XML序列化:反序列化抽象属性的问题

我仍然试图围绕整个xml序列化事物包围我的脑子,看起来我又需要一些帮助了。

我需要能够反序列化抽象类型的属性。 这种类型将随着时间的推移而添加许多不同的具体类型,并且在许多不同的模型中被引用,因此明确列出每种具体类型并不是理想的解决方案。

我已经阅读了XML序列化和inheritance类型线程,并提出了以下内容:

     

**

 namespace TestService { public class Page { [XmlElement("introCommand", Type = typeof(XmlCommandSerializer))] //[XmlElement(typeof(PlayElement))] **NOTE: the example works if I use this instead public AbstractCommandModel introCommand; } } 

**

 namespace TestService { public class AbstractCommandModel { } } 

**

 namespace TestService { public class PlayElement : AbstractCommandModel { } } 

**

 namespace TestService { public class XmlCommandSerializer : IXmlSerializable { // Override the Implicit Conversions Since the XmlSerializer // Casts to/from the required types implicitly. public static implicit operator AbstractCommandModel(XmlCommandSerializer o) { return o.Data; } public static implicit operator XmlCommandSerializer(AbstractCommandModel o) { return o == null ? null : new XmlCommandSerializer(o); } private AbstractCommandModel _data; ///  /// [Concrete] Data to be stored/is stored as XML. ///  public AbstractCommandModel Data { get { return _data; } set { _data = value; } } ///  /// **DO NOT USE** This is only added to enable XML Serialization. ///  /// DO NOT USE THIS CONSTRUCTOR public XmlCommandSerializer() { // Default Ctor (Required for Xml Serialization - DO NOT USE) } ///  /// Initialises the Serializer to work with the given data. ///  /// Concrete Object of the AbstractCommandModel Specified. public XmlCommandSerializer(AbstractCommandModel data) { _data = data; } #region IXmlSerializable Members public System.Xml.Schema.XmlSchema GetSchema() { return null; // this is fine as schema is unknown. } public void ReadXml(System.Xml.XmlReader reader) { // Cast the Data back from the Abstract Type. string typeAttrib = reader.GetAttribute("type"); // Ensure the Type was Specified if (typeAttrib == null) throw new ArgumentNullException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractCommandModel).Name + "' because no 'type' attribute was specified in the XML."); Type type = Type.GetType(typeAttrib); // Check the Type is Found. if (type == null) throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractCommandModel).Name + "' because the type specified in the XML was not found."); // Check the Type is a Subclass of the AbstractCommandModel. if (!type.IsSubclassOf(typeof(AbstractCommandModel))) throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractCommandModel).Name + "' because the Type specified in the XML differs ('" + type.Name + "')."); // Read the Data, Deserializing based on the (now known) concrete type. reader.ReadStartElement(); this.Data = (AbstractCommandModel)new XmlSerializer(type).Deserialize(reader); reader.ReadEndElement(); } public void WriteXml(System.Xml.XmlWriter writer) { // Write the Type Name to the XML Element as an Attrib and Serialize Type type = _data.GetType(); // BugFix: Assembly must be FQN since Types can/are external to current. writer.WriteAttributeString("type", type.AssemblyQualifiedName); new XmlSerializer(type).Serialize(writer, _data); } #endregion } } 

但是,当我运行反序列化器时,我得到一个InvalidOperationException,指出“XML文档中存在错误(3,3)”。 。 我在前面提到的线程中的例子中唯一改变的是类名。

我是否在正确的轨道上? 如果是这样,我搞砸了什么导致这个错误?

从你的例子:

 //[XmlElement(typeof(PlayElement))] **NOTE: the example works if I use this instead 

这是支持抽象类的推荐方法。 您可以按元素名称切换实例,并使用如下所示的多个声明:

 [XmlElement("playElement", typeof(PlayElement))] [XmlElement("testElement", typeof(TestElement))] public AbstractCommandModel Command; 

当然,您仍然需要删除“introCommand”元素或添加另一个类来嵌套上述声明。

如果您仍然需要手动进行序列化,那么您就在正确的路径上。 您的示例运行良好我想,这是XML输出:

      

而这个xml读取对象很好; 然而,这引起了安全问题。 任何有权修改或将此XML注入您的应用程序的人都可以轻松注入代码。

以下用于测试您的示例代码:

  private static void Main() { StringWriter dataOut = new StringWriter(); XmlTextWriter writer = new XmlTextWriter(dataOut); writer.Formatting = Formatting.Indented; Page p = new Page(); p.introCommand = new PlayElement(); new XmlSerializer(typeof(Page)).Serialize(writer, p); string xml = dataOut.ToString(); Console.WriteLine(xml); XmlTextReader reader = new XmlTextReader(new StringReader(xml)); Page copy = (Page) new XmlSerializer(typeof (Page)).Deserialize(reader); }