如何序列化其类相互引用的类层次结构,但避免 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? 的相关文章

  • C++ 长 switch 语句还是用地图查找?

    在我的 C 应用程序中 我有一些值充当代表其他值的代码 为了翻译代码 我一直在争论使用 switch 语句还是 stl 映射 开关看起来像这样 int code int value switch code case 1 value 10 b
  • linq 中使用字符串数组 c# 的 'orderby'

    假设我有一个这样的方法定义 public CustomerOrderData GetCustomerOrderData string CustomerIDs var query from a in db Customer join b in
  • 在 C# 中调用 C++ 库 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有很多用 C 编写的库 我想从 C 调用这些库 但是 我遇到了很多问题 我想知道是否有书籍或指南告诉我如何做到这一点 Dll导入 htt
  • 如何使用 SOAP 且不使用 WSE 在 .NET 中签署 Amazon Web 服务请求

    亚马逊产品广告 API 以前称为 Amazon Associates Web Service 或 Amazon AWS 实施了一项新规则 即自 2009 年 8 月 15 日起 向其发送的所有 Web 服务请求都必须经过签名 他们在其网站上
  • 检测到堆栈崩溃

    我正在执行我的 a out 文件 执行后 程序运行一段时间 然后退出并显示消息 stack smashing detected a out terminated Backtrace lib tls i686 cmov libc so 6 f
  • 一元 +/- 运算符如何可能导致“-a”或“+a”中的整数提升,“a”是算术数据类型常量/变量?

    这句看似微不足道的台词摘自我的迈克 巴纳汉和布雷迪的 C 书 第 2 8 8 2 节 http publications gbdirect co uk c book chapter2 expressions and arithmetic h
  • 获取 boost Spirit 语法中的当前行

    我正在尝试使用 boostspirit 获取正在解析的文件的当前行 我创建了一个语法类和结构来解析我的命令 我还想跟踪在哪一行找到命令并将其解析到我的结构中 我将 istream 文件迭代器包装在 multi pass 迭代器中 然后将其包
  • 使用查询表达式对 List 进行排序

    我在使用 Linq 订购这样的结构时遇到问题 public class Person public int ID get set public List
  • MFC:如何设置CEdit框的焦点?

    我正在开发我的第一个简单的 MFC 项目 但我正在努力解决一个问题 想要设置所有的焦点CEdit其中一个对话框中的框 我的想法是 当打开对话框时 焦点位于第一个编辑框上 然后使用 选项卡 在它们之间交换 我看到了方法SetFocus 但我无
  • 使用 C# 和 wpf 创建类似 Dock 的应用程序

    我需要创建一个与我们购买笔记本电脑时获得的应用程序类似的应用程序 仅当鼠标指针到达窗口顶部时它才可见 那么我怎样才能使用 C 4 0 来做到这一点呢 http www notebookcheck net uploads pics win2
  • 如何在三个 IEnumerable 上使用 Zip [重复]

    这个问题在这里已经有答案了 可能的重复 使用 Linq 从 3 个集合创建项目 https stackoverflow com questions 5284315 create items from 3 collections using
  • 搜索实体的所有字段

    我正在尝试在客户数据库上实现 多功能框 类型的搜索 其中单个查询应尝试匹配客户的任何属性 这是一些示例数据来说明我想要实现的目标 FirstName LastName PhoneNumber ZipCode Mary Jane 12345
  • 为什么 Cdecl 调用在“标准”P/Invoke 约定中经常不匹配?

    我正在开发一个相当大的代码库 其中 C 功能是从 C P Invoked 的 我们的代码库中有很多调用 例如 C extern C int stdcall InvokedFunction int 使用相应的 C DllImport CPlu
  • Project Euler #8,我不明白我哪里出了问题[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我正在做项目欧拉第八题 https projecteuler net problem 8 其中我得到了这个大得离谱的数字 7316
  • Linux mremap 不释放旧映射?

    我需要一种方法将页面从一个虚拟地址范围复制到另一个虚拟地址范围 而无需实际复制数据 范围很大 延迟很重要 mremap 可以做到这一点 但问题是它也会删除旧的映射 由于我需要在多线程环境中执行此操作 因此我需要旧映射能够同时使用 因此稍后当
  • 在 OpenGL 中渲染纹理 1 到 1

    所以我想做的是使用 OpenGL 和 C 将纹理渲染到平面上 作为显示图像的一种方式 但是我需要确保在渲染纹理时没有对纹理进行任何处理 抗锯齿 插值 平滑 模糊等 这是 OpenGL 处理渲染纹理的默认方式吗 或者是否需要设置一些标志才能禁
  • 逆向工程 ASP.NET Web 应用程序

    我有一个 ASP NET Web 应用程序 我没有源代码 该 bin 包含 10 个程序集和一个 compiled 文件 我在 App Code dll 上使用 Reflector 它向我显示了类和命名空间之类的东西 但它太混乱了 有没有什
  • 为什么以下 C 程序会出现总线错误?

    我认为这是第一个失败的 strtok 调用 好久没写C了 有点不知所措 非常感谢 include
  • 如何将 SQL“LIKE”与 LINQ to Entities 结合使用?

    我有一个文本框 允许用户指定搜索字符串 包括通配符 例如 Joh Johnson mit ack on 在使用 LINQ to Entities 之前 我有一个存储过程 该存储过程将该字符串作为参数并执行以下操作 SELECT FROM T
  • 如何使用placement new重新初始化该字段?

    我的课程包含字段 private OrderUpdate curOrderUpdate 我一遍又一遍地使用它 经常需要重新初始化 for int i 0 i lt entries size i auto entry entries i ne

随机推荐

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