JSON.net сериализует массив json в JArray, когда местом назначения является объект. Как я могу это изменить?
У меня есть один уровень JSON, который я хочу десериализовать в Dictionary<string,object>
используя Json.Net.
Значением словаря может быть примитив, строка или массив (примитив \ строка).
Десериализация знает, как обрабатывать примитивы и строки, но когда она попадает в массив примитивов, она десериализует ее в JArray
(вместо примитивного массива).
Вот небольшой пример кода того, что я имею в виду:
string jsonStr = @"{""obj"": 7, ""arr"": ['1','2','3']}";
Dictionary<string, object> dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonStr);
dict["obj"].GetType(); // long
dict["arr"].GetType(); // JArray. I would like this to be string[].
Я ищу способ, которым я могу вмешаться в процесс десериализации и создать примитивный массив вместо того, чтобы застрять JArray
,
Я пытался сделать это с JsonSerializerSettings
, но не мог прибить пятно.
2 ответа
Вот хакерский способ сделать это. Я создаю пользовательский класс JsonConverter, который принимает 2 общих аргумента: T1 и T2. T1 задает тип массива (в данном случае строка), а T2 - тип другого объекта (в данном случае long). Я предполагаю, что мы в основном хотим словарь, но эта часть определенно может быть улучшена.
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string jsonStr = @"{""obj"": 7, ""arr"": ['1','2','3']}";
Dictionary<string, object> dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonStr, new SpecialConverter<string, long>());
dict["obj"].GetType(); // long
dict["arr"].GetType(); // string[].
}
class SpecialConverter<T1, T2> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
var result = new Dictionary<string, object>();
if (result.GetType() == objectType)
{
foreach (var item in token)
{
var prop = (JProperty)item;
if (prop.Value.Type == JTokenType.Array)
{
result.Add(prop.Name, prop.Value.ToObject<T1[]>());
}
else
{
result.Add(prop.Name, prop.Value.ToObject<T2>());
}
}
return result;
}
else
{
return null;
}
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
}
}
Причина, по которой он не преобразуется в массив, заключается в том, что вы говорите JsonConvert преобразовать его в Dictionary<string, object>
и это именно то, что он делает, основываясь на том факте, что он не имеет конкретного Object
чтобы преобразовать, следовательно, он имеет "угадай" выбранный JArray. Если вы можете иметь несколько типов для значения словаря, лучше всего было бы преобразовать его в динамический объект. Это даст вам массив, если значением "arr" является массив или строка, если значением является простая строка.
string jsonStr = @"{""obj"": 7, ""arr"": ['1','2','3']}";
dynamic dict = JsonConvert.DeserializeObject(jsonStr);
var arr = dict.arr;
string firstelement = arr[0]; // print "1"