Unable to deserialize polymorphic dictionary json due to KnownType “__type” issue
我创建了一个包含多态值的字典,其中保存了一个类对象。我已成功序列化 JSON。但我无法反序列化它。它给出以下错误:
Element ‘:Value’ contains data of the ‘:Sale’ data contract. The deserializer has no knowledge of any type that maps to this contract.
如果将 JSON 属性 “__type” 替换为 “type” 则它可以工作,但无法恢复正确的对象类型。在序列化之前它包含我的类类型的对象,但在反序列化之后它包含一个 system.object 代替。
我的代码如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
using System;
using System.Collections.Generic; using System.Text; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; class Program //Code for JSON // Decode the thing Dictionary<string, object> result = new Dictionary<string, object>(); [DataContract] public Sale(int saleid, int total) public int getTotal() [DataContract(Name =“Restaurant”, Namespace=“”)] public Restaurant(string name, string city) |
小提琴链接:https://dotnetfiddle.net/CfQxxV
您正在尝试使用多态成员序列化根对象 Dictionary<string, object>。数据契约序列化程序使用白名单方法来处理多态性:在序列化过程中遇到的所有多态子类型必须事先通过已知类型机制声明,然后才能在序列化图中遇到该子类型的实例。
那么,如何使用您的数据模型来做到这一点?有几种方法:
将 [KnownType(typeof(TDerivedObject))] 直接添加到静态声明的基类型中,如 Joost K.
的答案所示
这不能在这里工作,因为基本类型是 Object,你不能修改它。
将 [KnownType(typeof(TDerivedObject))] 添加到序列化图中的某个父对象。
这看起来有问题,因为您的根对象类型是 Dictionary<string, object>,但是您可以对字典进行子类化以获得所需的结果:
1
2 3 4 5 |
然后使用这个子类构造和序列化你的字典:
1
2 3 4 5 6 7 8 |
这里是演示小提琴#1。
通过使用 DataContractJsonSerializerSettings 构造序列化程序,在运行时配置其他已知类型,其中已知类型在 DataContractJsonSerializerSettings.KnownTypes:
中指定
1
2 3 4 5 |
确保为序列化和反序列化以相同的方式配置序列化程序。
这里是演示小提琴#2。
(对于 XML,使用 DataContractSerializerSettings.KnownTypes。)
通过配置文件指定其他已知类型,如添加已知类型的其他方法中所示。
您是直接序列化,但如果您是通过 WCF 进行序列化,则可以将 ServiceKnownTypeAttribute 添加到您的服务合同中。
永远不需要将 [KnownType(typeof(TClass))] 添加到 TClass 本身,因此您可以从 Restaurant 和 sale 中删除此类属性:
1
2 3 4 5 6 |
[DataContract]
//[KnownType(typeof(Sale))] Remove this public class Sale { // Remainder unchanged } |
有关更多信息,请参阅 Sowmy Srinivasan 的所有关于 KnownTypes。
您遇到的问题是您将 [KnownType(typeof(…))] 放在 sale 和 Restaurant 之上。
使用 KnownType 的原因是为了在 1 和另一个对象之间进行转换。所以反序列化器不知道 sale 是 Object 的 KnownType。所以它不能将对象转换为销售。
只有当字典中的所有项目都共享一个公共父对象时,这才有效,如下所示:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[KnownType(typeof(Sale))]
[KnownType(typeof(Restaurant))] [KnownType(typeof(Employee))] [DataContract] public class SomeObject { } [DataContract(Name =“Sale”, Namespace=“”)] [DataContract(Name =“Restaurant”, Namespace=“”)] [DataContract(Name =“Employee”, Namespace=“”)] |
然后使用字典作为
1
|
- 感谢您的快速解决方案。它工作正常。我已经更新了小提琴。但我无法添加非对象。那么你有什么想法吗?这样我也可以在下面添加。 dict.Add(“雇员”,”约翰”);
- 它还需要是扩展 SomeObject 的对象,我稍微编辑了我的答案
来源:https://www.codenong.com/58835728/