Json.Net 通常将Dictionary<k,v>
序列化为集合;
"MyDict": {
"Apples": {
"Taste": 1341181398,
"Title": "Granny Smith",
},
"Oranges": {
"Taste": 9999999999,
"Title": "Coxes Pippin",
},
}
这很好。从SO环顾四周来看,这似乎是大多数人想要的。但是,在这种特殊情况下,我想在我的Dictionary<k,v>
和数组格式之间序列化;
"MyDict": [
"k": "Apples",
"v": {
"Taste": 1341181398,
"Title": "Granny Smith",
}
},
"k:": "Oranges",
"v:": {
"Taste": 9999999999,
"Title": "Coxes Pippin",
}
},
]
有没有一种简单的方法可以使用我现有的字段类型来做到这一点?例如,是否有我可以注释的属性?
实现此目的的另一种方法是使用自定义ContractResolver
。 这样,您就不必像其他答案中建议的那样,在每次序列化时都Dictionary<K,V>
子类化或应用转换。
以下解析器将导致所有字典序列化为具有"键"和"值"属性的对象数组:
class DictionaryAsArrayResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
if (objectType.GetInterfaces().Any(i => i == typeof(IDictionary) ||
(i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>))))
{
return base.CreateArrayContract(objectType);
}
return base.CreateContract(objectType);
}
}
要使用解析器,请将其添加到您的JsonSerializerSettings
,然后将设置传递给JsonConvert.SerializeObject()
,如下所示:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new DictionaryAsArrayResolver();
string json = JsonConvert.SerializeObject(obj, settings);
这是一个工作演示。
啊,事实证明这和我希望的一样简单。我的Dictionary<k,v>
已经被子类化了,我发现我可以用[JsonArrayAttribute]
注释它。这给了我我需要的格式;
"MyDict": [
{
"Key": "Apples",
"Value": {
"Taste": 1341181398,
"Title": "Granny Smith",
}
},
{
"Key:": "Oranges",
"Value:": {
"Taste": 9999999999,
"Title": "Coxes Pippin",
}
},
]
对于此示例,我将使用字典:
var myDict = new Dictionary<string,string>() {
{"a","123"},
{"b","234"},
{"c","345"}
};
将(使用 Newtonsoft.Json.JsonConvert.SerializeObject(myDict)
)序列化为:
{"a":"123","b":"234","c":"345"}
可以使用 LINQ 执行转换以创建匿名对象,并序列化该对象:
var myDictTransformed = from key in myDict.Keys
select new { k = key, v = myDict[key] };
或者你可以使用一个真实的对象
class MyDictEntry
{
public string k { get; set; }
public string v { get; set; }
}
以及上述或替代 LINQ 语法:
var myDictTransformed = myDict.Keys.AsEnumerable()
.Select(key => new MyDictEntry{
k = key,
v = myDict[key]
});
无论哪种方式,这都会序列化为:
[
{"k":"a", "v":"123"},
{"k":"b", "v":"234"},
{"k":"c", "v":"345"}
]
.NET 小提琴链接:https://dotnetfiddle.net/LhisVW
我发现的最简单的解决方案是将您的Dictionary<string, string>
转换为List<KeyValuePair<string, string>>
。 然后 JSON.NET 将您的List
转换为形式为 { Key: 'keyname', Value: 'value' }
的对象数组。如果您接受所需的模型更改并且不想对Dictionary
进行子类化,则此方法非常有效。
Gregmac的回答很有帮助,但并不完全有效。 以下是同样的想法...没有双关语。
var dictionaryTransformed = dictionary.Select(item => item.Key).Select(i =>
new {Key = i, Value = dictionary[i] });
或者当然
var dictionaryTransformed = dictionary.Select(item =>
new {item.Key, Value = dictionary[item.Key] });
然后到 json
var json = (new JavaScriptSerializer()).Serialize(
new { Container = dictionaryTransformed.ToArray() } )
我不确定为什么,但是上面列出的Brian Rogers的自定义ContractResolver对我不起作用。它似乎在内部的某个地方陷入了一个无休止的循环。可能是由于我的 json.net 设置的其他部分。
无论如何 - 这个解决方法为我做了诀窍。
public interface IStrongIdentifier
{
string StringValue { get; set; }
}
public class StrongIdentifierKeyedDictionaryWrapper<TKey, TValue> : Dictionary<string, TValue>
where TKey : IStrongIdentifier
{
public void Add(TKey key, TValue value)
{
base.Add(key.StringValue, value);
}
public void Remove(TKey key)
{
base.Remove(key.StringValue);
}
public TValue this[TKey index]
{
get => base[index.StringValue];
set => base[index.StringValue] = value;
}
public bool ContainsKey(TKey key)
{
return base.ContainsKey(key.StringValue);
}
}