问题描述
我有一个自定义 .net 类型作为其键的字典.我正在尝试使用 JSON.net 将此字典序列化为 JSON,但是它无法在序列化过程中将键转换为正确的值.
I have a dictionary with a custom .net Type as Its key.I am trying to serialize this dictionary to JSON using JSON.net, However its not able to Convert Keys to Proper Value during Serialization.
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":"Normal"}"
This Give me --> "{"JSonSerialization.ListBaseClass":"Normal"}"
但是,如果我将自定义类型作为 Dictionary 中的值,则效果很好
However if I have my Custom type as value in Dictionary it Works well
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);
这给我 --> "{"Normal":{"testA":"Hello","testB":"World"}}"
This Give me --> "{"Normal":{"testA":"Hello","testB":"World"}}"
如果我遇到了 Json.net 的一些限制或者我做错了什么,有人可以建议吗?
Can Someone Suggest If I am hitting some limitation of Json.net or I am doing Something Wrong?
推荐答案
您可能不想使用 Gordon Bean 提出的答案.该解决方案有效,但它提供了用于输出的序列化字符串.如果您使用的是 JSON,这将给您带来不太理想的结果,因为您确实想要对象的 JSON 表示,而不是字符串表示.
You probably don't want to use the answer that Gordon Bean presented. The solution works, but it provides a serialized string for output. If you are using JSON, this will give you a less than ideal result, since you really want a JSON representation of an object and not a string representation.
例如,假设您有一个将唯一网格点与字符串相关联的数据结构:
for example, let's suppose that you have a data structure that associates unique grid points with strings:
class Point
{
public int x { get; set; }
public int y { get; set; }
}
public Dictionary<Point,string> Locations { get; set; };
使用 TypeConverter 覆盖,当您序列化它时,您将获得该对象的字符串表示形式.
Using the TypeConverter override, you will get a string representation of this object when you serialize it.
"Locations": {
"4,3": "foo",
"3,4": "bar"
},
但我们真正想要的是:
"Locations": {
{ "x": 4, "y": 3 }: "foo",
{ "x": 3, "y": 4 }: "bar"
},
重写 TypeConverter 来序列化/反序列化类有几个问题.
There are several problems with overriding the TypeConverter to serialize / deserialize the class.
首先,这不是 JSON,您可能需要编写额外的自定义逻辑来处理其他地方的序列化和反序列化.(例如,可能是您的客户端层中的 Javascript?)
First, this is not JSON, and you might have to write additional custom logic to deal with serialize and deserialize it elsewhere. (perhaps Javascript in your client layer, for example?)
其次,使用此对象的任何其他地方现在都会喷出此字符串,之前它已正确序列化为对象:
Second, Anywhere else that uses this object will now spew this string, where previously it serialized properly to an object:
"GridCenterPoint": { "x": 0, "y": 0 },
现在序列化为:
"GridCenterPoint": "0,0",
你可以稍微控制一下 TypeConverter 的格式,但你无法摆脱它被呈现为字符串而不是对象的事实.
You can control the TypeConverter formatting a little, but you cannot get away from the fact it is rendered as a string and not an object.
这个问题不是序列化程序的问题,因为 Json.NET 会仔细检查复杂的对象而不会错过任何一个节拍,这是处理字典键的方式的问题.如果您尝试获取示例对象,并序列化 List 甚至 Hashset,您会注意到生成正确的 JSON 没有问题.这为我们提供了一种更简单的方法来解决这个问题.
This problem isn't a problem with the serializer, since Json.NET chews through complex objects without missing a beat, it is a problem with the way that dictionary keys are processed. If you try taking the example object, and serializing a List or even a Hashset, you notice that there isn't a problem producing proper JSON. This gives us a much simpler way to solve this problem.
理想情况下,我们只想告诉 Json.NET 将键序列化为任何对象类型,而不是将其强制为字符串.由于这似乎不是一个选项,另一种方法是为 Json.NET 提供可以使用的东西:List<KeyValuePair<T,K>>
.
Ideally, we would like to just tell Json.NET to serialize the key as whatever object type it is, and not force it to be a string. Since that doesn't seem to be an option, the other way is to give Json.NET something that it can work with: a List<KeyValuePair<T,K>>
.
如果您将 KeyValuePairs 列表输入 Json.NET 的序列化程序,您将得到您所期望的.例如,这是一个您可以实现的更简单的包装器:
If you feed a list of KeyValuePairs into Json.NET's serializer, you get exactly what you expect. For example, here is a much simpler wrapper that you could implement:
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); }
}
这个技巧很有效,因为 kvp 中的键不会被强制转换为字符串格式.你问为什么是字符串格式?它打败了我.Dictionary 对象实现了 IEnumerable<KeyValuePair<TKey, TValue>>
接口,因此以与 kvps 列表相同的方式对其进行序列化应该没有任何问题,因为这本质上就是字典是.有人(詹姆斯牛顿?)在编写 Newtonsoft 字典序列化程序时做出了一个决定,即复杂的键太乱而无法处理.可能有一些我没有考虑过的极端情况使这个问题变得更加棘手.
This trick works, because keys in a kvp aren't forced into string format. Why a string format, you ask? It beats the hell out of me. the Dictionary object implements the IEnumerable<KeyValuePair<TKey, TValue>>
interface, so there shouldn't be any problem in serializing it in the same fashion as the list of kvps, since that is essentially what a dictionary is. Someone (James Newton?) made a decision when writing the Newtonsoft dictionary serializer that complex keys were too messy to deal with. There are probably some corner cases I have not considered that make this a much more sticky problem.
这是一个更好的解决方案,因为它生成实际的 JSON 对象,技术上更简单,并且不会产生因替换序列化程序而导致的任何副作用.
This is a much better solution because it produces actual JSON objects, is technically simpler, and doesn't produce any side effects resulting from replacing the serializer.
这篇关于无法使用 Json.net 序列化具有复杂键的字典的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!