This question already has an answer here:
这个问题已经有了答案:
- How do I use JSON.NET to deserialize into nested/recursive Dictionary and List? 5 answers
- 如何使用JSON。反序列化为嵌套/递归字典和列表?5个回答
I'm trying to convert some older work to use Newtonsoft JSON.NET. The default handling using the System.Web.Script.Serialization.JavaScriptSerializer.Deserialize
method (e.g. if no target type is specified) is to return a Dictionary<string,object>
for inner objects.
我正在尝试将一些旧的工作转换为使用Newtonsoft JSON.NET。使用system . web . script. serializ.javascriptserializer的默认处理。反序列化方法(例如,如果没有指定目标类型)是返回一个字典
This is actually a really useful basic type for JSON since it also happens to be the underlying type used by ExpandoObjects
and is the most sensible internal implementation for dynamic types.
这实际上是JSON的一种非常有用的基本类型,因为它恰好是ExpandoObjects使用的底层类型,也是动态类型最合理的内部实现。
If I specify this type, e.g.:
如果我指定这个类型,例如:
var dict = JsonConvert.DeserializeObject<Dictionary<string,object>>(json);
JSON.NET will deserialize the outermost object structure correctly, but it returns a JObject
type for any inner structures. What I really need is for the same outer structure to be used for any inner object-type structures.
JSON。NET将对最外层的对象结构进行正确的反序列化,但它将返回任何内部结构的JObject类型。我真正需要的是用于任何内部对象类型结构的相同的外部结构。
Is there a way to specify a type to be used for inner objects, and not just the outermost type returned?
是否有一种方法可以指定用于内部对象的类型,而不只是返回的最外层类型?
2 个解决方案
#1
7
When Deserializing your complex objects using Json, you need to add a JsonSerializer Settings as a parameter. This will ensure that all of the inner types get deserialized properly.
当使用Json反序列化您的复杂对象时,您需要添加一个JsonSerializer设置作为参数。这将确保所有的内部类型都得到正确的反序列化。
private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full
};
When Serializing your object, you can use the SerializerSettings:
在序列化对象时,可以使用SerializerSettings:
string json= JsonConvert.SerializeObject(myObject, _jsonSettings)
Then when you are deserializing, use:
当你反序列化时,使用:
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, _jsonSettings);
Also, when you serialize, add the JsonSerializerSettings to your SerializeObject(object, settings)
此外,在序列化时,将JsonSerializerSettings添加到SerializeObject(对象、设置)
Edit: You can also change the TypeNameHandling and TypeNameAssemblyFormat if you need to. I have them set at 'All' and 'Full' respectively to ensure that my complex objects get serialized and deserialized properly without doubt, but intellisense provides you with other alternatives
编辑:如果需要的话,您还可以更改TypeNameHandling和typename汇编格式。我将它们分别设置为“All”和“Full”,以确保我的复杂对象毫无疑问地得到序列化和反序列化,但是intellisense为您提供了其他选择。
#2
15
In order to get Json.Net to deserialize a json string into an IDictionary<string, object>
including deserializing nested objects and arrays you will need to create a custom class that derives from the JsonConverter
abstract class provided by Json.Net.
为了得到Json。Net将json字符串反序列化为IDictionary
It is in your derived JsonConverter
where you put the implementation of how an object should be written to and from json.
它是在您的派生JsonConverter中,您将如何将对象写入和从json写入的实现。
You can use your custom JsonConverter
like this:
您可以使用这样的自定义JsonConverter:
var o = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, new DictionaryConverter());
Here is a custom JsonConverter I have used with success in the past to achieve the same goals as you outline in your question:
这里有一个自定义的JsonConverter,我在过去用它来实现与你的问题相同的目标:
public class DictionaryConverter : JsonConverter {
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { this.WriteValue(writer, value); }
private void WriteValue(JsonWriter writer, object value) {
var t = JToken.FromObject(value);
switch (t.Type) {
case JTokenType.Object:
this.WriteObject(writer, value);
break;
case JTokenType.Array:
this.WriteArray(writer, value);
break;
default:
writer.WriteValue(value);
break;
}
}
private void WriteObject(JsonWriter writer, object value) {
writer.WriteStartObject();
var obj = value as IDictionary<string, object>;
foreach (var kvp in obj) {
writer.WritePropertyName(kvp.Key);
this.WriteValue(writer, kvp.Value);
}
writer.WriteEndObject();
}
private void WriteArray(JsonWriter writer, object value) {
writer.WriteStartArray();
var array = value as IEnumerable<object>;
foreach (var o in array) {
this.WriteValue(writer, o);
}
writer.WriteEndArray();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
return ReadValue(reader);
}
private object ReadValue(JsonReader reader) {
while (reader.TokenType == JsonToken.Comment) {
if (!reader.Read()) throw new JsonSerializationException("Unexpected Token when converting IDictionary<string, object>");
}
switch (reader.TokenType) {
case JsonToken.StartObject:
return ReadObject(reader);
case JsonToken.StartArray:
return this.ReadArray(reader);
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Undefined:
case JsonToken.Null:
case JsonToken.Date:
case JsonToken.Bytes:
return reader.Value;
default:
throw new JsonSerializationException
(string.Format("Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
}
}
private object ReadArray(JsonReader reader) {
IList<object> list = new List<object>();
while (reader.Read()) {
switch (reader.TokenType) {
case JsonToken.Comment:
break;
default:
var v = ReadValue(reader);
list.Add(v);
break;
case JsonToken.EndArray:
return list;
}
}
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
}
private object ReadObject(JsonReader reader) {
var obj = new Dictionary<string, object>();
while (reader.Read()) {
switch (reader.TokenType) {
case JsonToken.PropertyName:
var propertyName = reader.Value.ToString();
if (!reader.Read()) {
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
}
var v = ReadValue(reader);
obj[propertyName] = v;
break;
case JsonToken.Comment:
break;
case JsonToken.EndObject:
return obj;
}
}
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
}
public override bool CanConvert(Type objectType) { return typeof(IDictionary<string, object>).IsAssignableFrom(objectType); }
}
#1
7
When Deserializing your complex objects using Json, you need to add a JsonSerializer Settings as a parameter. This will ensure that all of the inner types get deserialized properly.
当使用Json反序列化您的复杂对象时,您需要添加一个JsonSerializer设置作为参数。这将确保所有的内部类型都得到正确的反序列化。
private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full
};
When Serializing your object, you can use the SerializerSettings:
在序列化对象时,可以使用SerializerSettings:
string json= JsonConvert.SerializeObject(myObject, _jsonSettings)
Then when you are deserializing, use:
当你反序列化时,使用:
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, _jsonSettings);
Also, when you serialize, add the JsonSerializerSettings to your SerializeObject(object, settings)
此外,在序列化时,将JsonSerializerSettings添加到SerializeObject(对象、设置)
Edit: You can also change the TypeNameHandling and TypeNameAssemblyFormat if you need to. I have them set at 'All' and 'Full' respectively to ensure that my complex objects get serialized and deserialized properly without doubt, but intellisense provides you with other alternatives
编辑:如果需要的话,您还可以更改TypeNameHandling和typename汇编格式。我将它们分别设置为“All”和“Full”,以确保我的复杂对象毫无疑问地得到序列化和反序列化,但是intellisense为您提供了其他选择。
#2
15
In order to get Json.Net to deserialize a json string into an IDictionary<string, object>
including deserializing nested objects and arrays you will need to create a custom class that derives from the JsonConverter
abstract class provided by Json.Net.
为了得到Json。Net将json字符串反序列化为IDictionary
It is in your derived JsonConverter
where you put the implementation of how an object should be written to and from json.
它是在您的派生JsonConverter中,您将如何将对象写入和从json写入的实现。
You can use your custom JsonConverter
like this:
您可以使用这样的自定义JsonConverter:
var o = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, new DictionaryConverter());
Here is a custom JsonConverter I have used with success in the past to achieve the same goals as you outline in your question:
这里有一个自定义的JsonConverter,我在过去用它来实现与你的问题相同的目标:
public class DictionaryConverter : JsonConverter {
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { this.WriteValue(writer, value); }
private void WriteValue(JsonWriter writer, object value) {
var t = JToken.FromObject(value);
switch (t.Type) {
case JTokenType.Object:
this.WriteObject(writer, value);
break;
case JTokenType.Array:
this.WriteArray(writer, value);
break;
default:
writer.WriteValue(value);
break;
}
}
private void WriteObject(JsonWriter writer, object value) {
writer.WriteStartObject();
var obj = value as IDictionary<string, object>;
foreach (var kvp in obj) {
writer.WritePropertyName(kvp.Key);
this.WriteValue(writer, kvp.Value);
}
writer.WriteEndObject();
}
private void WriteArray(JsonWriter writer, object value) {
writer.WriteStartArray();
var array = value as IEnumerable<object>;
foreach (var o in array) {
this.WriteValue(writer, o);
}
writer.WriteEndArray();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
return ReadValue(reader);
}
private object ReadValue(JsonReader reader) {
while (reader.TokenType == JsonToken.Comment) {
if (!reader.Read()) throw new JsonSerializationException("Unexpected Token when converting IDictionary<string, object>");
}
switch (reader.TokenType) {
case JsonToken.StartObject:
return ReadObject(reader);
case JsonToken.StartArray:
return this.ReadArray(reader);
case JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
case JsonToken.Boolean:
case JsonToken.Undefined:
case JsonToken.Null:
case JsonToken.Date:
case JsonToken.Bytes:
return reader.Value;
default:
throw new JsonSerializationException
(string.Format("Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
}
}
private object ReadArray(JsonReader reader) {
IList<object> list = new List<object>();
while (reader.Read()) {
switch (reader.TokenType) {
case JsonToken.Comment:
break;
default:
var v = ReadValue(reader);
list.Add(v);
break;
case JsonToken.EndArray:
return list;
}
}
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
}
private object ReadObject(JsonReader reader) {
var obj = new Dictionary<string, object>();
while (reader.Read()) {
switch (reader.TokenType) {
case JsonToken.PropertyName:
var propertyName = reader.Value.ToString();
if (!reader.Read()) {
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
}
var v = ReadValue(reader);
obj[propertyName] = v;
break;
case JsonToken.Comment:
break;
case JsonToken.EndObject:
return obj;
}
}
throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
}
public override bool CanConvert(Type objectType) { return typeof(IDictionary<string, object>).IsAssignableFrom(objectType); }
}