Подтвердить что ты не робот

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",
    }
  },
]

Есть ли простой способ сделать это с моим существующим типом поля? Есть ли атрибут, который я могу аннотировать, например?

4b9b3361

Ответ 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() } )