【问题标题】:XML version-specific deserializationXML 版本特定的反序列化
【发布时间】:2015-06-02 18:13:20
【问题描述】:

所以,我有一个基础项目和几个修改版本。 BaseProject 包含类BaseClass,

namespace BaseProject.SomeClasses{
    public abstract class BaseClass{
    //...
    }
}

虽然每个版本都包含多个 BaseClass 的继承者 - f.e. ProjectOne

namespace BaseProject.VersionOne.SomeClasses{
    public class InheritorClass : BaseClass{
    //Some logic here...
    }
}

ProjectTwo

namespace BaseProject.VersionTwo.SomeClasses{
    public class InheritorClass : BaseClass{
    //Some different logic here...
    }
}

唯一不同的是命名空间的名称。

基础项目在运行时加载每个程序集并获取所有继承的类型。我需要创建 xml 文件,该文件应包含继承者的实例和一些指向应将实例反序列化为的类的指针:

...
<BaseClass xsi:type="InheritorClass"> <!-- From VersionOne -->
    <PropOne></PropOne>
    <PropTwo></PropTwo>
    <PropThree></PropThree>
    <!-- ... -->
</BaseClass>
<BaseClass xsi:type="InheritorClass"> <!-- From VersionTwo -->
    <PropFour></PropFour>
    <PropFive></PropFive>
    <PropSix></PropSix>
    <!-- ... -->
</BaseClass>
...

有没有办法将这个xml(包含两个版本的继承者的实例)反序列化为IEnumerable&lt;BaseClass&gt;

【问题讨论】:

  • 您需要使用给定的命名空间限定您的元素
  • @MartinCh,好的,但是如果我只能在运行时访问后者,如何链接 xml 命名空间和 C# 命名空间?
  • 我没有得到你想要实现的逻辑 - 基类是父类 - 你的继承者类 - 被继承 - 专业化 - 你不能在不失去员工的情况下将孩子放回父类添加到孩子中
  • @MartinCh,每个继承者类都有与父类相同的方法,所以我可以重写它们并使用特定于继承者的参数。

标签: c# xml serialization xmlserializer


【解决方案1】:

您需要将[XmlTypeAttribute(name)] 属性应用于派生类以消除xst:type 名称的歧义:

namespace BaseProject.VersionOne.SomeClasses
{
    [XmlType("VersionOneInheritorClass")]
    public class InheritorClass : BaseClass
    {
        public string VersionOneProperty { get; set; } // For instance
    }
}

namespace BaseProject.VersionTwo.SomeClasses
{
    [XmlType("VersionTwoInheritorClass")]
    public class InheritorClass : BaseClass
    {
        public string VersionTwoProperty { get; set; } // For instance
    }
}

那么你的XML会出现如下,并且可以序列化和反序列化成功而不会丢失信息:

<BaseClass xsi:type="VersionOneInheritorClass">
    <VersionOneProperty>one</VersionOneProperty>
</BaseClass>
<BaseClass xsi:type="VersionTwoInheritorClass">
    <VersionTwoProperty>two</VersionTwoProperty>
</BaseClass>

顺便说一句,如果您使用XmlSerializer (Type, Type[]) 构造函数构造XmlSerializer 以添加您发现的派生类型,则必须cache the serializer in a static cache somewhere,否则您将遇到可怕的资源泄漏。

【讨论】:

  • 好吧,我还对 Serializer 进行了一些定制,效果非常好!谢谢!
【解决方案2】:

类的命名空间不应该有所作为。请参阅此代码生成的 XML 文件。

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

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            Root root = new Root()
            {
                baseClass = new List<BaseClass>(){
                    new InheritorClass1(){ name = "class1"},
                    new InheritorClass2(){ name = "class2"}
                }
            };
            XmlSerializer serializer = new XmlSerializer(typeof(Root));

            StreamWriter writer = new StreamWriter(FILENAME);
            serializer.Serialize(writer, root);
            writer.Flush();
            writer.Close();
            writer.Dispose();

            XmlSerializer xs = new XmlSerializer(typeof(Root));
            XmlTextReader reader = new XmlTextReader(FILENAME);
            Root newRoot = (Root)xs.Deserialize(reader);
        }
    }
    [XmlRoot("Root")]
    public class Root
    {
        [XmlElement("BaseClass")]
        public List<BaseClass> baseClass { get; set; }
    }
    [XmlRoot("BaseClass")]
    [XmlInclude(typeof(InheritorClass1))]
    [XmlInclude(typeof(InheritorClass2))]
    public class BaseClass
    {
        [XmlElement("name")]
        public string name { get; set; }    

    }
    [XmlRoot("InheritorClass1")]
    public class InheritorClass1 : BaseClass
    {
    }

    [XmlRoot("InheritorClass2")]
    public class InheritorClass2 : BaseClass
    {
    }

}
​

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    相关资源
    最近更新 更多