我可以使用 DataContract 序列化程序序列化 Dictionary 吗?

2024-05-01

我计划构建一个 WCF 服务,返回序列化为 JSON 的通用字典对象。不幸的是,序列化失败,因为对象可能总是不同的。 KnownTypes 没有帮助,因为属性类型是 Dictionary,而且我不能说 KnownType,因为类可能总是不同。

如果可以序列化“未知类型”,有什么想法吗?

我不介意为每个类指定 DataContract/DataMember,但是(至少对于原型版本)我不想为每个响应都指定强类型。 Javascript 客户端并不关心。

匿名类怎么样?


NOTE:我在答案开始时详细介绍了 JavaScriptSerializer,如果您只想阅读原始问题中提到的已知类型问题的解决方案,请跳到答案的末尾。

表现

基于基准 http://theburningmonk.com/benchmarks/我跑了一下,JavaScriptSerializer 比其他替代方案慢得多,并且与 DataContractSerializer 相比,序列化/反序列化对象所需的时间是 DataContractSerializer 的 2 倍。

不需要已知类型

也就是说,JavascriptSerializer 更灵活,因为它不需要您提前指定“已知类型”,并且序列化的 JSON 至少在字典的情况下更干净(请参阅示例here http://theburningmonk.com/2011/05/json-serialization-datacontractjsonserializer-vs-javascriptserializer/).

围绕已知类型的灵活性的另一面是,它无法将相同的 JSON 字符串反序列化回原始类型。例如,假设我有一个简单的Person class:

public class Person
{
    public string Name { get; set; }

    public int Age { get; set; }
}

如果我创建一个实例Dictinoary<string, object>并添加一个实例Person在序列化之前对其进行类化:

var dictionary = new Dictionary<string, object>();
dictionary.Add("me", new Person { Name = "Yan", Age = 30 });
var serializer = new new JavaScriptSerializer();
var json = serializer .Serialize(dictionary);

我将得到以下 JSON{"me":{"Name":"Yan","Age":30}}它非常干净,但没有任何类型信息。所以假设如果你有两个具有相同成员定义的类或者如果Person在不引入任何其他成员的情况下进行子类化:

public class Employee : Person
{
}

那么序列化器根本无法保证 JSON{"Name":"Yan","Age":30}可以反序列化为正确的类型。

如果你反序列化{"me":{"Name":"Yan","Age":30}}使用 JavaScriptSerializer,在字典中你得到的与“me”相关的值不是一个实例Person but a Dictionary<string, object>取而代之的是一个简单的财产袋。

如果你想获得一个Person回到实例,你可以(尽管你很可能永远不想!)转换它Dictionary<string, object>使用ConvertToType辅助方法:

var clone = serializer.Deserialize<Dictionary<string, object>>(json);
var personClone = serializer.ConverToType<Person>(clone["me"]);

另一方面,如果您不需要担心将这些 JSON 反序列化为正确的类型,并且 JSON 序列化不是性能瓶颈(分析您的代码并找出序列化花费了多少 CPU 时间,如果您还没有这样做的话)已经)那么我会说只使用 JavaScriptSerializer。

注入已知类型

如果最终您仍然需要使用 DataContractSerializer 并需要注入这些 KnownType,那么您可以尝试以下两件事。

1)将已知类型的数组传递给DataContractSerializer构造函数 http://msdn.microsoft.com/en-us/library/bb908209.aspx.

2)传递一个子类数据契约解析器 http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractresolver.aspx(能够找到您感兴趣的类型)到 DataContractSerializer构造函数 http://msdn.microsoft.com/en-us/library/bb908209.aspx

您可以创建一个“已知类型注册表”来跟踪可以添加到字典中的类型,如果您控制需要注入 DataContractSerializer 的所有类型,您可以尝试最简单的方法:

  1. 创建一个KnownTypeRegister具有静态方法的类将类型添加到已知类型列表:

    
    public static class KnownTypeRegister
    {
        private static readonly ConcurrentBag _knownTypes = new ConcurrentBag();
        public static void Add(Type type)
        {
            _knownTypes.Add(type);
        }
        public static IEnumerable Get()
        {
            return _knownTypes.ToArray();
        }
    }  
  2. 添加一个静态构造函数,用寄存器注册类型:

    
    [DataContract]
    public class Person
    {
        static Person()
        {
            KnownTypeRegister.Add(typeof(Person));
        }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Age { get; set; }
    }  
  3. 构造序列化器时从寄存器获取已知类型的数组:

var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), KnownTypeRegister.Get());

更多动态/更好的选项是可能的,但它们也更难实现,如果您想了解有关动态已知类型解析的更多信息,请查看 Juval Lowy 的 MSDN 主题文章here http://msdn.microsoft.com/en-us/magazine/gg598929.aspx. Also, 这篇博文 http://blogs.msdn.com/b/carlosfigueira/archive/2011/09/21/wcf-extensibility-data-contract-resolver.aspxCarlos Figueira 还详细介绍了更先进的技术,例如动态生成类型,在您讨论该主题时非常值得一读!

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

我可以使用 DataContract 序列化程序序列化 Dictionary 吗? 的相关文章

随机推荐

  • 将自连接重写为 JPQL

    我需要将此自连接转换为 JPQL SELECT s1 FROM site AS s1 JOIN SELECT site type MAX last update date AS LastUpdate FROM site WHERE site
  • 对于特定用户 MySQL,查找同一表内的日期范围重叠

    我绝不是 MySQL 专家 所以我正在寻求有关此事的任何帮助 我需要执行一个简单的测试 原则上 我有这个 简化的 表 tableid userid car From To 1 1 Fiesta 2015 01 01 2015 01 31 2
  • 为什么我在 iOS 设备测试中收到“Building MacinTalk voice for asset: (null)”

    我正在设备上执行以下文本转语音项目代码 但收到错误 为资产构建 MacinTalk 语音 null 请帮助我解决问题或提示出现了什么问题 AVSpeechSynthesizer synthesizer AVSpeechSynthesizer
  • 在 Angular 中使用多个模块有什么好处?

    我是 Angular Js 的熟悉者 最近我发现在一些项目中 在主模块中创建并组装了多个 Angular 模块 代码看起来像 angular module main main sub1 main sub2 main sub2 angular
  • 将 Mailjet API v3 包装器集成为 Codeigniter 库

    我怎样才能整合Mailjet API PHP 包装器 https github com mailjet mailjet apiv3 php no composer作为库安装到我的 Codeigniter 安装中 是不是把内容放进去那么简单存
  • 如何控制 Pepper QiSDK 上的 LED?

    On NAOqi框架2 5有一个模块可以让你控制机器人的 LED 灯ALLeds 有类似的东西可以让我控制 Pepper 的 LED 灯吗 不 没有 截至 2020 年 1 月 在 Pepper QiSDK 中 LED 状态自动取决于 Pe
  • Xcode 6.1 Swift 扩展 - SourceKit 服务崩溃

    我正在尝试向 Swift 添加扩展 以便我可以格式化双精度数 如在此答案中找到的那样 Swift 中的精确字符串格式说明符 https stackoverflow com questions 24051314 precision strin
  • Angular:如何从 HttpClient 下载文件?

    我需要从我的后端下载一个Excel 它返回一个文件 当我执行请求时 我收到错误 类型错误 您在需要流的地方提供了 未定义 你 可以提供 Observable Promise Array 或 Iterable 我的代码是 this http
  • 快速查看生成器 iOS

    有没有办法扩展 iOS 上的快速查找框架来处理未知的文件类型 就像在 Mac 上一样 我不想切换到我的应用程序来预览文件 就像在电子邮件或 iMessage 中查看图像文件一样 我想删除必须选择使用哪个应用程序来打开文件的步骤 在 Mac
  • Oracle 10 中的本地临时表(适用于存储过程的范围)

    我是甲骨文新手 我需要在存储过程中处理大量数据 我正在考虑使用临时表 我正在使用连接池 并且该应用程序是多线程的 有没有一种方法可以为每次调用存储过程创建不同的表实例来创建临时表 以便来自多个存储过程调用的数据不会混淆 你说你是 Oracl
  • Visual Studio 代码调试器未连接到 SAM 本地

    根据 AWS 文档 我将像这样启动本地 SAM sam local start api d 5858 我的 launch json 中有以下内容 version 0 2 0 configurations name Attach to SAM
  • 如何更改“go build”的库路径

    我正在尝试与 goncurses 一起工作 在 Centos 6 上 ncurses 库很旧 5 7 想要 5 9 所以我从源代码构建了 ncurses 并将其安装到 usr lib usr include 等中 如何告诉 go get 针
  • 使用异步收集 Publisher 值

    我一直在为我们拥有的一些组合代码编写一些单元测试 我遇到了一些问题 我想我已经简化了这个测试中的各个部分 注意 这不是一个测试 这是我试图理解为什么其中一个测试不起作用 func test collectingPassthroughValu
  • 如何以 Express 方式传输响应?

    我一直在尝试让一个快速应用程序以流形式发送响应 var Readable require stream Readable var rs Readable app get report function req res res statusC
  • VideoView SeekTo 在不同设备上工作异常 - Android

    我在视频视图上使用此代码来寻求自定义位置 但它在三星设备上工作正常 但在索尼设备上 视频寻求开始位置 开始 我想让视频回到上次暂停的位置 创建视频视图 VideoView mVideoPlayer setVideoPath ViDpath
  • RS 232 中断信号

    我有一个RS232信号捕获设备 而且效果很好 我需要一些帮助来理解数据 基本上我们购买它是因为我们正在处理 80 年代末使用串行通信的机器控制器 尽管知道端口参数 但我们运气不佳 从我转储的数据来看 机器控制正在使用中断信号作为其协议的一部
  • 如何禁用 django-rest-framework 的管理风格可浏览界面?

    我在用django rest framework http django rest framework org 它提供了一个很棒的 Django 管理风格的可浏览的自文档 API 但任何人都可以访问这些页面并使用该界面添加数据 POST 我
  • 如何使用 Material-ui@next TextField 错误道具

    我想使用 Material UI Next 文本字段error props link https material ui next com api text field textfield 道具类型为boolean 之前版本的 Materi
  • 将日期添加到日历热图 R

    I m plotting a calender heat map using Paul Bleicher s calenderHeat R code https raw githubusercontent com iascchen VisH
  • 我可以使用 DataContract 序列化程序序列化 Dictionary 吗?

    我计划构建一个 WCF 服务 返回序列化为 JSON 的通用字典对象 不幸的是 序列化失败 因为对象可能总是不同的 KnownTypes 没有帮助 因为属性类型是 Dictionary 而且我不能说 KnownType 因为类可能总是不同