Sha*_*pta 32 c# serialization json dictionary json.net
我有一个自定义.net类型的字典作为其关键.我正在尝试使用JSON.net将此字典序列化为JSON,但是它无法在序列化期间将键转换为适当的值.
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);
Run Code Online (Sandbox Code Playgroud)
这个给我 - >"{\"JSonSerialization.ListBaseClass \":\"Normal \"}"
但是,如果我将自定义类型作为字典中的值,则可以正常工作
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);
Run Code Online (Sandbox Code Playgroud)
这个给我 - >"{\"普通\":{\"testA \":\"Hello \",\"testB \":\"World \"}}"
有人建议如果我遇到Json.net的某些限制或我做错了什么?
Gor*_*ean 26
该序列化向导状态(参见:字典和哈希表;感谢你@Shashwat的链接):
序列化字典时,字典的键将转换为字符串并用作JSON对象属性名称.为密钥编写的字符串可以通过覆盖密钥类型的ToString()或通过实现TypeConverter来自定义.在反序列化字典时,TypeConverter还将支持再次转换自定义字符串.
我找到了一个有用的示例,说明如何在Microsoft的"操作方法"页面上实现这种类型的转换器:
基本上,我需要扩展System.ComponentModel.TypeConverter
和覆盖:
bool CanConvertFrom(ITypeDescriptorContext context, Type source);
object ConvertFrom(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value);
object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture,
object value, Type destinationType);
Run Code Online (Sandbox Code Playgroud)
还必须将该属性添加 [TypeConverter(typeof(MyClassConverter))]
到MyClass
类声明中.
有了这些,我就能够自动序列化和反序列化字典.
您可能不想使用Gordon Bean提出的答案。该解决方案有效,但是它提供了输出的序列化字符串。如果您使用的是JSON,这将给您带来不太理想的结果,因为您确实需要对象的JSON表示形式而不是字符串表示形式。
例如,假设您有一个将唯一的网格点与字符串相关联的数据结构:
class Point
{
public int x { get; set; }
public int y { get; set; }
}
public Dictionary<Point,string> Locations { get; set; };
Run Code Online (Sandbox Code Playgroud)
使用TypeConverter覆盖,在序列化该对象时,将获得该对象的字符串表示形式。
"Locations": {
"4,3": "foo",
"3,4": "bar"
},
Run Code Online (Sandbox Code Playgroud)
但是我们真正想要的是:
"Locations": {
{ "x": 4, "y": 3 }: "foo",
{ "x": 3, "y": 4 }: "bar"
},
Run Code Online (Sandbox Code Playgroud)
覆盖TypeConverter以序列化/反序列化类存在几个问题。
首先,它不是JSON,您可能必须编写其他自定义逻辑来处理序列化和反序列化。(例如,可能是客户端层中的Javascript?)
其次,现在使用该对象的其他任何地方都会喷出该字符串,之前该字符串已正确序列化为一个对象:
"GridCenterPoint": { "x": 0, "y": 0 },
Run Code Online (Sandbox Code Playgroud)
现在序列化为:
"GridCenterPoint": "0,0",
Run Code Online (Sandbox Code Playgroud)
您可以稍微控制TypeConverter的格式设置,但是不能逃避将其呈现为字符串而不是对象的事实。
这个问题不是序列化程序的问题,因为json.net在不丢失节奏的情况下咀嚼复杂的对象,因此处理字典键的方式存在问题。如果尝试使用示例对象并序列化List甚至是Hashset,则会注意到生成适当的JSON没有问题。这为我们提供了解决此问题的简单得多的方法。
理想情况下,我们只想告诉json.net将键序列化为任何对象类型,而不是将其强制为字符串。由于这似乎不是一种选择,所以另一种方法是给json.net它可以使用的东西:a List<KeyValuePair<T,K>>
。
如果将KeyValuePairs列表输入到json.net的序列化器中,则将得到您所期望的结果。例如,这是一个可以实现的简单得多的包装器:
private Dictionary<Point, string> _Locations;
public List<KeyValuePair<Point, string>> SerializedLocations
{
get { return _Locations.ToList(); }
set { _Locations= value.ToDictionary(x => x.Key, x => x.Value); }
}
Run Code Online (Sandbox Code Playgroud)
这个技巧行得通,因为kvp中的键不会强制转换为字符串格式。你问为什么呢?它使我不寒而栗。Dictionary对象实现了该IEnumerable<KeyValuePair<TKey, TValue>>
接口,因此以与kvps列表相同的方式对其进行序列化应该没有任何问题,因为从本质上讲,这就是kvps列表的含义。编写Newtonsoft字典序列化程序时,有人(詹姆斯·牛顿(James Newton?))做出了一个决定,即复杂的键难以处理。我可能没有想到一些极端的情况,这使这个问题变得更加棘手。
这是一个更好的解决方案,因为它可以生成实际的JSON对象,在技术上更简单,并且不会由于替换序列化程序而产生任何副作用。
归档时间: |
|
查看次数: |
11395 次 |
最近记录: |