XML序列化和继承的类型 [英] XML Serialization and Inherited Types

查看:141
本文介绍了XML序列化和继承的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从我的<一继href=\"http://stackoverflow.com/questions/19454/enforce-attribute-decoration-of-classesmethods\">$p$pvious问题我一直在努力让我的对象模型的序列化到XML。不过,我现在已经运行到一个问题(广利惊喜!)。

Following on from my previous question I have been working on getting my object model to serialize to XML. But I have now run into a problem (quelle surprise!).

我的问题是,我有一个集合,它是一个抽象基类,这是由具体的派生类型填充的。

The problem I have is that I have a collection, which is of a abstract base class type, which is populated by the concrete derived types.

我认为这将是罚款,只需添​​加的XML属性涉及到所有的类,一切都将是桃色的。可悲的是,那不是如此!

I thought it would be fine to just add the XML attributes to all of the classes involved and everything would be peachy. Sadly, thats not the case!

所以,我已经做了一些挖掘在谷歌,我现在理解的为什么的它不工作。在的XmlSerializer 其实是在做一些聪明的反映,以序列化对象/从XML,并且因为它的基础上,抽象类型,它想不通到底是怎么回事了它的交谈。精细。

So I have done some digging on Google and I now understand why it's not working. In that the XmlSerializer is in fact doing some clever reflection in order to serialize objects to/from XML, and since its based on the abstract type, it cannot figure out what the hell it's talking to. Fine.

我也遇到上$ C $的CProject此页面,它看起来像它很可能有很大的帮助(尚未读/消费完全),但我想我愿意把这个问题给StackOverflow的表格也一样,就看你有任何整洁黑客/为了过关获得这件事,并在运行最快/最轻的可能的方式。

I did come across this page on CodeProject, which looks like it may well help a lot (yet to read/consume fully), but I thought I would like to bring this problem to the StackOverflow table too, to see if you have any neat hacks/tricks in order to get this up and running in the quickest/lightest way possible.

有一件事我还要补充的是,我的不要要下井 XmlInclude 路线。有一个与它简直太耦合和系统的这一领域仍处于开发状态,所以这将是一个真正的维修头痛!

One thing I should also add is that I DO NOT want to go down the XmlInclude route. There is simply too much coupling with it, and this area of the system is under heavy development, so the it would be a real maintenance headache!

推荐答案

好了,我终于到了那里(当然有帮助,从的许多 =HTTP://www.$c$cproject.com/KB/XML/xmlserializerforunknown.aspx >此处!)。

Problem Solved!

OK, so I finally got there (admittedly with a lot of help from here!).

所以,总结一下:


  • 我不想给的 XmlInclude 的路线走下来,由于maintenence头痛。

  • 一旦找到了解决办法,我想它要快于其他应用程序来实现。

  • 可以使用抽象类型的集合,以及个人的抽象属性。

  • 我真的不希望有不必做特殊的事情在具体的类打扰。

  • I didn't want to go down the XmlInclude route due to the maintenence headache.
  • Once a solution was found, I wanted it to be quick to implement in other applications.
  • Collections of Abstract types may be used, as well as individual abstract properties.
  • I didn't really want to bother with having to do "special" things in the concrete classes.

  • 的XmlSerializer 的做一些pretty冷思考,但它的非常的,当谈到抽象类型(即它只能与抽象类型的实例工作有限本身,而不是子类)。

  • XML特性装饰定义的XmlSerializer如何对待性质的认定。物理类型也可以指定,但是这创造类和串行(不好)之间的紧耦合

  • 我们可以通过创建一个类,它实现的的IXmlSerializable 的实施我们自己的XmlSerializer。

  • XmlSerializer does some pretty cool reflection, but it is very limited when it comes to abstract types (i.e. it will only work with instances of the abstract type itself, not subclasses).
  • The Xml attribute decorators define how the XmlSerializer treats the properties its finds. The physical type can also be specified, but this creates a tight coupling between the class and the serializer (not good).
  • We can implement our own XmlSerializer by creating a class that implements IXmlSerializable .

我创建了一个泛型类,在其中指定的泛型类型,你将要使用的抽象类型。这使类的抽象类型和具体类型之间的翻译,因为我们可以硬code的能力,铸造(即我们可以得到更多信息比XmlSerializer的可以)。

I created a generic class, in which you specify the generic type as the abstract type you will be working with. This gives the class the ability to "translate" between the abstract type and the concrete type since we can hard-code the casting (i.e. we can get more info than the XmlSerializer can).

然后我实施的的IXmlSerializable 的接口,这是pretty向前伸直,但序列化的时候,我们必须确保我们写的具体类到XML的类型,所以我们可以投它回来时,反序列化。同样重要的是要注意它必须完全合格的因为这两个类是有可能不同的组件。当然有,需要在这里发生一个小的类型检查和东西。

I then implemented the IXmlSerializable interface, this is pretty straight forward, but when serializing we need to ensure we write the type of the concrete class to the XML, so we can cast it back when de-serializing. It is also important to note it must be fully qualified as the assemblies that the two classes are in are likely to differ. There is of course a little type checking and stuff that needs to happen here.

由于XmlSerializer的不能投,我们需要提供code要做到这一点,所以后来的隐式操作符重载(我从来不知道你能做到这一点!)。

Since the XmlSerializer cannot cast, we need to provide the code to do that, so the implicit operator is then overloaded (I never even knew you could do this!).

在code为AbstractXmlSerializer是这样的:

The code for the AbstractXmlSerializer is this:

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

namespace Utility.Xml
{
    public class AbstractXmlSerializer<AbstractType> : IXmlSerializable
    {
        // Override the Implicit Conversions Since the XmlSerializer
        // Casts to/from the required types implicitly.
        public static implicit operator AbstractType(AbstractXmlSerializer<AbstractType> o)
        {
            return o.Data;
        }

        public static implicit operator AbstractXmlSerializer<AbstractType>(AbstractType o)
        {
            return o == null ? null : new AbstractXmlSerializer<AbstractType>(o);
        }

        private AbstractType _data;
        /// <summary>
        /// [Concrete] Data to be stored/is stored as XML.
        /// </summary>
        public AbstractType Data
        {
            get { return _data; }
            set { _data = value; }
        }

        /// <summary>
        /// **DO NOT USE** This is only added to enable XML Serialization.
        /// </summary>
        /// <remarks>DO NOT USE THIS CONSTRUCTOR</remarks>
        public AbstractXmlSerializer()
        {
            // Default Ctor (Required for Xml Serialization - DO NOT USE)
        }

        /// <summary>
        /// Initialises the Serializer to work with the given data.
        /// </summary>
        /// <param name="data">Concrete Object of the AbstractType Specified.</param>
        public AbstractXmlSerializer(AbstractType 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(AbstractType).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(AbstractType).Name +
                    "' because the type specified in the XML was not found.");

            // Check the Type is a Subclass of the AbstractType.
            if (!type.IsSubclassOf(typeof(AbstractType)))
                throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).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 = (AbstractType)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
    }
}

所以,从那里,我们怎么告诉XmlSerializer的与我们的串行而不是默认的工作?内部的XML属性类型属性,例如我们必须通过我们的类型:

So, from there, how do we tell the XmlSerializer to work with our serializer rather than the default? We must pass our type within the Xml attributes type property, for example:

[XmlRoot("ClassWithAbstractCollection")]
public class ClassWithAbstractCollection
{
    private List<AbstractType> _list;
    [XmlArray("ListItems")]
    [XmlArrayItem("ListItem", Type = typeof(AbstractXmlSerializer<AbstractType>))]
    public List<AbstractType> List
    {
        get { return _list; }
        set { _list = value; }
    }

    private AbstractType _prop;
    [XmlElement("MyProperty", Type=typeof(AbstractXmlSerializer<AbstractType>))]
    public AbstractType MyProperty
    {
        get { return _prop; }
        set { _prop = value; }
    }

    public ClassWithAbstractCollection()
    {
        _list = new List<AbstractType>();
    }
}

在这里你可以看到,我们有一个集合和一个单一的财产被曝光,而我们需要做的就是添加的键入的命名参数以XML声明,方便! :D

Here you can see, we have a collection and a single property being exposed, and all we need to do is add the type named parameter to the Xml declaration, easy! :D

注:如果您使用此code,我真的AP preciate呼喊出。这也将有助于推动更多的人到社区:)

现在,但不能确定是什么在这里的答案做,因为他们都有自己的亲的和反对的。我会upmod那些我觉得是有用的(没有冒犯那些没有),并关闭这个功能,一旦我有代表:)

Now, but unsure as to what to do with answers here since they all had their pro's and con's. I'll upmod those that I feel were useful (no offence to those that weren't) and close this off once I have the rep :)

有趣的问题,解决好好玩! :)

Interesting problem and good fun to solve! :)

这篇关于XML序列化和继承的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆