如何序列化其类相互引用的类层次结构,但避免 XmlInclude?

2024-04-27

我有一个类的层次结构,我想使用XmlSerializer类及其相关属性。有一个基本抽象类,然后是相当多的派生类(在下面的代码中,我已将派生类的数量减少到五个,但实际代码中还有更多)。这些类形成一个层次结构,并且经常包含对层次结构中类的实例的引用。

public abstract class BaseType 
{
    // Only classes in my assembly can derive from this class
    internal BaseType() { }   
}

public sealed class TType : BaseType
{
    [XmlText]
    public string Name;
}

public sealed class PType : BaseType
{
    [XmlElement("t", typeof(TType)]
    [XmlElement("p", typeof(PType)]
    [XmlElement("a", typeof(AType)]
    [XmlElement("s", typeof(SType)]
    [XmlElement("u", typeof(UType)]
    public BaseType Child;
}

public sealed class SType : BaseType
{
    [XmlElement("t", typeof(TType)]
    [XmlElement("p", typeof(PType)]
    [XmlElement("s", typeof(SType)]
    [XmlElement("a", typeof(AType)]
    [XmlElement("u", typeof(UType)]
    public BaseType [] Items;
    public string [] ItemNames;
}

public sealed class AType : BaseType
{
    [XmlElement("t", typeof(TType)]
    [XmlElement("p", typeof(PType)]
    [XmlElement("s", typeof(SType)]
    [XmlElement("a", typeof(AType)]
    [XmlElement("u", typeof(UType)]
    public BaseType Item;
    public int Length;
}

public sealed class UType : BaseType
{
    [XmlElement("t", typeof(TType)]
    [XmlElement("p", typeof(PType)]
    [XmlElement("s", typeof(SType)]
    [XmlElement("a", typeof(AType)]
    [XmlElement("u", typeof(UType)]
    public BaseType [] Alts;
    public string [] AltNames;
}

最后,一个容器可以容纳所有这些并喂给XmlSerializer:

[XmlRoot("items")]
public class ItemCollection
{
    [XmlElement("t", typeof(TType)]
    [XmlElement("p", typeof(PType)]
    [XmlElement("s", typeof(SType)]
    [XmlElement("a", typeof(AType)]
    [XmlElement("u", typeof(UType)] 
    public BaseType [] Items;
}

正如您所看到的,我的代码中有相当多的重复。在某些时候,可能会引入一个新的派生类,并且所有使用 BaseType 引用的地方都必须使用新的派生类重新访问。XmlElement属性。这既乏味又容易出错。我想表达一个事实BaseType如果元素名称为“t”,则可以反序列化为 TType;如果元素名称为“p”,则可以反序列化为 PType,等等,仅一次。

我知道XmlIncludeAttribute但它介绍了xsi:type“金主”不满意的属性。有什么方法可以分解出 XML 元素名称和 CLR 类型之间的映射知识吗?

解决方案可以做出的一个假设是定义派生类的程序集已知BaseType。这意味着我们不必考虑将新类添加到外部程序集中。


经过一段时间的摆弄后,我想出了一个解决方案,并在这里发布以帮助处于相同情况的其他人。

首先,找到类型层次结构中的所有类型。然后编写一个函数来构建XmlElements包含所有这些类型的实例:

XmlAttributes CreateXmlAttributesForHierarchyTypes()
{
    return XmlAttributes
    {
        XmlElements = 
        {
            new XmlElementAttribute("t", typeof (TType)),
            new XmlElementAttribute("p", typeof (PType)),
            new XmlElementAttribute("s", typeof (SType)),
            new XmlElementAttribute("a", typeof (AType)),
            new XmlElementAttribute("u", typeof (UType)),
        }
    };
}

现在找到具有您希望序列化的上述类型之一的字段的所有类型。您可以通过反映程序集中的所有类来做到这一点,但就我而言,我碰巧知道只有少数类具有此要求:

Type [] typesToOverride = new Type[] 
{
    typeof(PType),
    typeof(SType),
    typeof(AType),
    typeof(UType),
    typeof(ItemCollection),
};

我们现在继续创建一个实例XmlAttributeOverrides指定了hierarchyTypeElements覆盖适当类型的每个字段:

public static XmlAttributeOverrides GetAttributeOverrides(IEnumerable<Type> typesToOverride)
{
    var overrides = typesToOverride
        .SelectMany(x => x.GetFields())  // Get a flat list of fields from all the types
        .Where(f => f.FieldType == typeof (BaseType))  // Must have the right type
        .Select(f => new
        {
            Field = f,
            Attributes = GetXmlAttributes(f)
        })
        .Where(f => f.Attributes != null)
        .Aggregate(
            new XmlAttributeOverrides(),
            (ov, field) =>
            { 
                ov.Add(field.Field.DeclaringType, field.Field.Name, field.Attributes); 
                return ov;
            });
    return overrides;
}

(是啊,我滥用Aggregate; LinQ 真是一把简洁的金锤子)

最后使用XmlAttributeOverrides创建序列化器的实例:

var attrOverrides = GetAttributeOverrides(TypesToDecorate);
serializer = new XmlSerializer(typeof(ItemCollection), attrOverrides);

您可能希望将该序列化程序缓存在静态变量中以避免泄漏程序集。

这段代码可以推广到修饰属性和字段。这留给读者作为练习。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何序列化其类相互引用的类层次结构,但避免 XmlInclude? 的相关文章

随机推荐

  • 在 Express + NodeJS 应用程序的控制器中使用 ES6 类或对象文字

    有两件事我很困惑 使用任何 ES6 类或对象文字的优点是什么 我应该在哪里使用它们 下面提到了我正在尝试的一些示例 请让我知道何时使用特定的实现方式 何时不使用 类例1 auth js class Auth login req res si
  • 使用嵌套对象进行 Hapi/Joi 验证

    我对我的其中一条路线进行了以下验证 payload keywordGroups Joi array items Joi object keys language Joi string required containsAny Joi arr
  • 从一个 Nodejs 应用程序调用另一个 Nodejs 应用程序中的 API 的方法

    我们的应用程序将有一个网站和一个移动应用程序 两者都与同一个 API 后端进行通信 我有一个仅提供 API 服务的 Nodejs 应用程序 还有一个为网站提供 html 页面服务的 Nodejs 应用程序 我正在为这两个应用程序使用 Exp
  • 指向基类的基本多态指针

    虽然我已经在 C 领域工作了一段时间 但直到现在我才需要使用多态特性 而且我对它们非常感兴趣 如果我有一个基类ClassA和另一个ClassB从中衍生出来 我明白我可以拥有virtual中的成员函数ClassA即 当实施于ClassB 将被
  • 如何将带有子查询的 JPQL 转换为 Criteria API 等效项?

    有一个由 5 个实体组成的简单对象模型 Company 组织 Address Club Group 公司与单个组织相关联 团体和俱乐部也与单个组织相关联 它们是单向的 这意味着组织不包含对其所有者的引用 一个组织可以有 0 个或多个地址 子
  • python3导入找不到模块

    我正在尝试测试书中的一个例子 我得到了一个ImportError 该示例开始如下 from tkinter import from PP4E Gui Tools widgets import frame button entry 如果我放一
  • 如何使用 Android Studio 调试器后退一行代码

    我是调试器的新手 当我跨过一行代码时 我想知道如何后退 现在我意识到代码不能向后执行 如果我想退回到旧行 是否必须重新启动调试活动 另外 如果您不介意的话 强制步入命令是什么 不要认为这是可能的 Android 的工作方式与所有其他调试器一
  • java 对字母数字字符串进行排序

    我有这个数组存储用户添加的一些 URL 的后缀 U2 U3 U1 U5 U8 U4 U7 U6 当我这样做时 for Map
  • 调用程序中对库类成员的未定义引用错误

    下面添加了其他问题 2011 年 4 月 11 日 我正在用 C 开发一组跨平台的共享库 DLL Sos 和测试程序 尽管我必须能够支持 C 这些库将仅作为目标代码发布 但测试程序将随源代码一起发布 因此我们的客户可以获得示例代码 因此 我
  • 使用 Go 解组嵌套 xml

    我有以下代码片段 我一直在努力让它工作 我到处寻找解决方案 但我找到的解决方案似乎都不起作用 我的映射似乎有问题xml Unmarshal命令 因为它涉及嵌套字段 下面的代码用于检索第一个被称为的值unit 并且位于 xml 代码的顶层 另
  • WPF 进度条动画速度

    我注意到 WPF 进度栏和 WinForms 进度栏完全填满所需的时间存在差异 完全填充 就像在 Form 和 WPF 中将值设置为 100 一样 我们可以注意到 WinForms 平滑地填充栏 而 WPF 立即填充它 我想知道是否有一个属
  • 如何摆脱“Google 地图方向服务”标记?

    谷歌地图Direction ServiceApi有两个 副作用 1 它添加了Markers自动到达出发地和目的地 2 它增加了两个InfoWindow到新的Markers 包含他们的地址 知道如何摆脱这些标记及其信息气泡吗 添加suppre
  • QSpinBox 具有用于十六进制输入的 Unsigned Int

    这里写了很多关于 QSpinBox 使用 int 作为其数据类型的限制的问题 人们通常希望显示更大的数字 就我而言 我希望能够以十六进制显示无符号 32 位整数 这意味着我希望我的范围为 0x0 0xFFFFFFFF 正常的 QSpinBo
  • 如何使用 Dapper 将字符串作为 NULL 发送到 SQLServer?

    我有一个场景 C 中的字符串可以是null 我需要它是NULL在 SQL Server 上 我使用 Dapper 将其发送到 SQLServer 查询如下 connection Query
  • 面向 Clojure 用户的 Java

    我一直在断断续续地使用 Lisp 并且正在赶上 clojure clojure的好处是我可以自然地使用所有的java函数 而clojure的坏处也是我必须自然地了解java函数 例如 我不得不花一些时间 谷歌搜索 来查找 Java 中的平方
  • 如何在 AngularJS 中插入命令或阻止 $http 的 JSONP 自动解析?

    似乎我发现的关于 http 或 angularjs 的几乎每个问题或解释通常都假设您可以修改请求的响应 我不能这样做 而且我得到的响应格式错误 根据 AngularJS 解析器 它的格式错误一致 因此我可以在解析纯文本之前修改它来解决问题
  • 当我传递 NULL 值时,COALESCE 函数不起作用,但当将变量声明为 NULL 时它起作用

    当我执行以下查询时 我得到输出 但是当我通过NULL参数 它不起作用 示例1 DECLARE a int NULL b int NULL c int NULL SELECT COALESCE a b c GO 输出 空 示例2 SELECT
  • 如何使用 jasper 从 jsp 生成 pdf 格式的报告

    在我的应用程序中 我可以连接到数据库并获取数组结果集 并使用 JSP 代码迭代该数组并使用 HTML 在网页中显示报告 我希望 HTML 网页中生成的报告可以以 PDF 格式导出并保存在某个 pdf 文件中 请告诉我如何实现这样的技术来实现
  • 雪豹中的 OpenVRML(来自 macports)

    嘿 我刚刚从 macports 下载了 openvrml 端口安装openvrml 现在我有一个示例程序 来自 sourceforge 的 openvrml 的 pretty print cpp 其开头如下 ifdef HAVE CONFI
  • 如何序列化其类相互引用的类层次结构,但避免 XmlInclude?

    我有一个类的层次结构 我想使用XmlSerializer类及其相关属性 有一个基本抽象类 然后是相当多的派生类 在下面的代码中 我已将派生类的数量减少到五个 但实际代码中还有更多 这些类形成一个层次结构 并且经常包含对层次结构中类的实例的引