我有一个字典,其键为自定义.net类型。我尝试使用www.example.com将此字典序列化为JSONJSON.net,但在序列化过程中无法将键转换为正确的值。
class ListBaseClass
{
public String testA;
public String testB;
}
-----
var details = new Dictionary<ListBaseClass, string>();
details.Add(new ListBaseClass { testA = "Hello", testB = "World" }, "Normal");
var results = Newtonsoft.Json.JsonConvert.SerializeObject(details);
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<ListBaseClass, string>> results);
这给予我--〉“{\“JSonSerialization.ListBaseClass":\“正常"}”
但是,如果我有我的自定义类型作为字典中的值,它工作得很好
var details = new Dictionary<string, ListBaseClass>();
details.Add("Normal", new ListBaseClass { testA = "Hello", testB = "World" });
var results = Newtonsoft.Json.JsonConvert.SerializeObject(details);
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, ListBaseClass>>(results);
这给予我--〉“{\“正常":{\“测试A":\“您好",\“测试B":\“世界"}}”
有人能建议我是否遇到了www.example.com的一些限制Json.net或我做错了什么吗?
7条答案
按热度按时间tzcvj98z1#
你可能不想使用Gordon Bean给出的答案。这个解决方案是可行的,但是它提供了一个序列化的字符串作为输出。如果你使用JSON,这将给予你一个不太理想的结果,因为你真正想要的是一个对象的JSON表示,而不是字符串表示。
例如,假设您有一个将唯一网格点与字符串相关联的数据结构:
使用TypeConverter重写,您将在序列化此对象时获得它的字符串表示形式。
但我们真正想要的是:
重写TypeConverter以序列化/反序列化类存在几个问题。
首先,这不是JSON,您可能需要编写额外的自定义逻辑来处理序列化和反序列化。(例如,可能在客户端层编写Javascript?)
第二,使用该对象的任何其他地方现在都将抛出该字符串,而以前它将正确地序列化为一个对象:
现在序列化为:
您可以稍微控制TypeConverter的格式设置,但无法摆脱它呈现为字符串而不是对象的事实。
这个问题并不是序列化器的问题,因为Json .NET可以不间断地处理复杂的对象,而是字典键的处理方式的问题。如果你尝试使用示例对象,序列化一个List或者甚至是一个Hashset,你会注意到生成正确的JSON并没有问题。这给了我们一个更简单的方法来解决这个问题。
理想情况下,我们只想告诉Json .NET将键序列化为任何对象类型,而不是将其强制为字符串。由于这似乎不是一个选项,因此另一种方法是为Json .NET提供一些它可以使用的东西:a x 1m 0n 1x。
如果您将KeyValuePair列表提供给Json .NET的序列化程序,您将得到您所期望的结果。例如,下面是一个您可以实现的简单得多的 Package 器:
从@bmw15评论更新:
您可以将Dictionary prop设置为公共属性,向其添加[JsonIgnore],并使用[JsonProperty]属性将KeyValuePair列表设置为私有属性
这个技巧很有效,因为kvp中的键不会被强制转换成字符串格式。你会问为什么是字符串格式?这把我难住了。Dictionary对象实现了
IEnumerable<KeyValuePair<TKey, TValue>>
接口,所以以与kvp列表相同的方式序列化它应该没有任何问题。因为这就是字典的本质(JamesNewton?)在编写Newtonsoft字典序列化程序时做出了一个决定,即复杂的键太乱,无法处理。可能有一些角落的情况下,我没有考虑到,使这是一个更棘手的问题。这是一个更好的解决方案,因为它生成实际的JSON对象,技术上更简单,并且不会产生任何替换序列化程序所带来的副作用。
jtoj6r0c2#
Serialization Guide状态(参见章节:字典和哈希表谢谢你@Shashwat的链接):
序列化字典时,字典的键将转换为字符串并用作JSON对象属性名。通过重写键类型的ToString()或实现TypeConverter,可以自定义为键编写的字符串。TypeConverter还支持在反序列化字典时将自定义字符串再次转换回来。
我在Microsoft的“how-to”页面上找到了一个关于如何实现这种类型转换器的有用示例:
实际上,我需要扩展
System.ComponentModel.TypeConverter
并覆盖:还必须将属性
[TypeConverter(typeof(MyClassConverter))]
添加到MyClass
类声明中。有了这些,我就能够 * 自动 * 序列化和反序列化字典了。
qxsslcnc3#
另一种方法是使用自定义ContractResolver并设置OverrideCreator。
用法:
agyaoht74#
在@roger-hill answer之后,我想出了一个轻量级的解决方案来达到同样的效果:
通过这种方式,每个
MyDictionary
对象都被序列化为键/值对的数组,对于复杂的键类型也能正常工作:dhxwm5r45#
灵感来自gson enableComplexMapKeySerialization及其外观/工作原理:
可以创建与Tal Aloni代码相同的json,但作为JsonConverter而不是契约。更灵活,因为它可以使用JsonConverterAttribute在选定属性上使用,也可以使用JsonSerializerSettings.Converters.Add(...)在所有属性上使用
xpszyzbs6#
基于@roger-hill富有洞察力的回答,我创建了下面的
JsonConverter
,它将把一个IDictionary
对象转换成KeyValuePair
对象的List
。github link
我做了一些测试,这段代码在测试中运行良好......但我可能漏掉了一两个边缘情况。
sdnqo3pr7#
一切都更容易
样品