Json.Net - Сериализованный словарь как массив (пары ключевых значений)
Json.Net обычно сериализует Dictionary<k,v>
в коллекцию;
"MyDict": {
"Apples": {
"Taste": 1341181398,
"Title": "Granny Smith",
},
"Oranges": {
"Taste": 9999999999,
"Title": "Coxes Pippin",
},
}
Это здорово. И, глядя на SO, похоже, это то, чего хотят большинство людей. Однако в этом конкретном случае я хочу сериализовать между моим Dictionary<k,v>
и форматом Array;
"MyDict": [
"k": "Apples",
"v": {
"Taste": 1341181398,
"Title": "Granny Smith",
}
},
"k:": "Oranges",
"v:": {
"Taste": 9999999999,
"Title": "Coxes Pippin",
}
},
]
Есть ли простой способ сделать это с моим существующим типом поля? Есть ли атрибут, который я могу аннотировать, например?
Ответы
Ответ 1
А, оказывается, это так же просто, как я надеялся. Мой Dictionary<k,v>
уже подклассифицирован, и я обнаружил, что могу его аннотировать с помощью [JsonArrayAttribute]
. Это дает мне именно тот формат, который мне нужен;
"MyDict": [
{
"Key": "Apples",
"Value": {
"Taste": 1341181398,
"Title": "Granny Smith",
}
},
{
"Key:": "Oranges",
"Value:": {
"Taste": 9999999999,
"Title": "Coxes Pippin",
}
},
]
Ответ 2
Другой способ добиться этого - использовать пользовательский ContractResolver
. Таким образом, вам не нужно подкласса Dictionary<K,V>
и не применять преобразование при каждом сериализации, как это предлагается в других ответах.
Следующий резольвер приведет к сериализации ALL словарей как массива объектов с свойствами "Key" и "Value":
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);
Ниже приведена рабочая демонстрация.
Ответ 3
В этом примере я воспользуюсь изречением:
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 Fiddle: https://dotnetfiddle.net/LhisVW
Ответ 4
Самое простое решение, которое я нашел, - это преобразовать Dictionary<string, string>
в List<KeyValuePair<string, string>>
. Затем JSON.NET преобразует ваш List
в массив объектов с формой { Key: 'keyname', Value: 'value' }
. Это хорошо работает, если вы принимаете требуемое изменение модели и не хотите подклассифицировать Dictionary
.
Ответ 5
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() } )