Так вот моя проблема. У меня есть класс, который выглядит примерно так...
public class Record
{
public string Name { get; set; }
public KeyValuePair<string, object> Details { get; set; }
}
И вот базовый пример того, как может выглядеть экземпляр...
var root = new Record
{
Name = "Root",
Details = new KeyValuePair<string, object>("TestSerialization",
new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("IsChild", true),
new KeyValuePair<string, object>("Child1", "Another KV pair")
})
};
Я хочу сериализовать этот объект в JSON, но я хочу немного изменить процесс. Поэтому, когда я сериализую этот объект, я хочу, чтобы JSON выглядел примерно так...
{
"Name" : "Root",
"Details" :
{
"TestSerialization" :
[
{ "IsChild" : true },
{ "Child1" : "Another KV pair" }
]
}
}
Но похоже, что большинство сериализаторов сериализуют пары ключ-значение в нечто подобное...
{
//...
{ "key" : "IsChild", "value" : true }
//...
}
Есть ли писатель или сериализатор, который может это сделать?
И Json.Net, и встроенный.NET JavaScriptSerializer могут предоставить вам нужный вам результат, если вы захотите написать собственный класс конвертера. Интерфейс для каждой каркасной версии конвертера совсем другой, но общая идея такая же. Я продемонстрирую оба в этом ответе.
В Json.Net вам нужно будет реализовать класс JsonConverter
. Метод CanConvert
сообщает Json.Net, какой тип объектов (ов) может обрабатывать конвертер, а метод WriteJson
обрабатывает преобразование каждого экземпляра в JSON с использованием JsonWriter
и JsonSerializer
переданных методу.
class KvpConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(KeyValuePair<string, object>);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var kvp = (KeyValuePair<string, object>)value;
writer.WriteStartObject();
writer.WritePropertyName(kvp.Key);
serializer.Serialize(writer, kvp.Value);
writer.WriteEndObject();
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Вот демонстрация, показывающая, как использовать преобразователь при сериализации:
class Program
{
static void Main(string[] args)
{
var root = new Record
{
Name = "Root",
Details = new KeyValuePair<string, object>("TestSerialization",
new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("IsChild", true),
new KeyValuePair<string, object>("Child1", "Another KV pair")
})
};
var settings = new JsonSerializerSettings();
settings.Converters.Add(new KvpConverter());
settings.Formatting = Formatting.Indented;
string json = JsonConvert.SerializeObject(root, settings);
Console.WriteLine(json);
}
}
public class Record
{
public string Name { get; set; }
public KeyValuePair<string, object> Details { get; set; }
}
Вывод:
{
"Name": "Root",
"Details": {
"TestSerialization": [
{
"IsChild": true
},
{
"Child1": "Another KV pair"
}
]
}
}
Версия.Net-конвертера называется JavaScriptConverter
. Подобно Json.Net, свойство SupportedTypes
сообщает JavaScriptSerializer
какие типы объектов обрабатывает конвертер, в то время как метод Serialize
отвечает за изменение формы вывода. Основное отличие состоит в том, что в Serialize
вы не имеете прямого контроля над выходом JSON; вместо этого вы создаете и возвращаете IDictionary<string, object>
который сериализатор затем сериализуется вместо исходного объекта, который вы конвертируете. Так что не такая гибкая, как Json.Net, но этого достаточно, чтобы получить то, что нам нужно в этом случае. Вот как выглядит код для JavaScriptConverter:
class KvpJavaScriptConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new List<Type> { typeof(KeyValuePair<string, object>) }; }
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
KeyValuePair<string, object> kvp = (KeyValuePair<string, object>)obj;
Dictionary<string, object> dict = new Dictionary<string, object>();
dict.Add(kvp.Key, kvp.Value);
return dict;
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
}
Вот обновленный демо-код:
class Program
{
static void Main(string[] args)
{
var root = new Record
{
Name = "Root",
Details = new KeyValuePair<string, object>("TestSerialization",
new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("IsChild", true),
new KeyValuePair<string, object>("Child1", "Another KV pair")
})
};
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(
new List<JavaScriptConverter> { new KvpJavaScriptConverter() });
string json = serializer.Serialize(root);
Console.WriteLine(json);
}
}
Результат такой же, как и для демонстрации Json.Net, за исключением того, что JavaScriptSerializer не поддерживает вывод с отступом.
JavaScriptSerializer
для сериализации, посмотрите пример, который я привел.JavaScriptSerializer
иJsonConvert
дали один иJsonConvert
же результат, я думаю, что лучше использовать сторонний DDL.JsonConvert
том, что если вJSS
есть основная функциональность, то зачем переходить на сторонние DLL, что скажете?