JSON.net 如何控制大量异构对象的反序列化
How to control deserialization of large array of heterogenous objects in JSON.net
我正在使用 JSON 作为中间格式从旧的专有对象数据库格式迁移数据。对象被输出到一个 JSON 对象数组中,每个对象都有一个初始字段,给出原始对象的类型,后跟一个名为 Instance 的字段,该字段具有嵌套的原始对象。
我需要将它们流式传输,因为可能有数十万个 - 我不能只将整个 JSON 数组读入内存然后处理它。
所以 JSON 看起来像这样:
[
{
"Type": "Foo",
"Instance": {
// instance of Foo type
}
},
{
"Type": "Bar",
"Instance": {
// instance of Bar type
}
},
// tens or hundreds of thousands more objects...
]
使用 Json.NET,一次传入一个数组元素的最佳方法是什么,访问 "Type" 属性,然后将 "Instance" 反序列化为 .适当类型的网络对象?
编辑:虽然有一个关于读取大型 JSON 数组的类似问题,但该问题没有回答访问实例的具体问题。
汇总
的答案
- Deserialize json array stream one item at a time
- Deserializing polymorphic json classes without type information using json.net,
首先,假设您有一个将类型名称映射到类型的自定义 SerializationBinder
(或类似的东西)。
接下来,您可以使用以下扩展方法枚举流式 JSON 数据中的顶级对象(遍历 进入 顶级数组):
public static class JsonExtensions
{
public static IEnumerable<JObject> WalkObjects(TextReader textReader)
{
using (JsonTextReader reader = new JsonTextReader(textReader))
{
while (reader.Read())
{
if (reader.TokenType == JsonToken.StartObject)
{
JObject obj = JObject.Load(reader);
if (obj != null)
{
yield return obj;
}
}
}
}
}
}
然后,假设您有一些 stream
用于读取您的 JSON 数据,您可以将 JSON 流式传输并逐一转换顶级数组元素以进行处理,如下所示:
SerializationBinder binder = new MyBinder(); // Your custom binder.
using (var stream = GetStream(json))
using (var reader = new StreamReader(stream, Encoding.Unicode))
{
var assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
var items = from obj in JsonExtensions.WalkObjects(reader)
let jType = obj["Type"]
let jInstance = obj["Instance"]
where jType != null && jType.Type == JTokenType.String
where jInstance != null && jInstance.Type == JTokenType.Object
let type = binder.BindToType(assemblyName, (string)jType)
where type != null
select jInstance.ToObject(type); // Deserialize to bound type!
foreach (var item in items)
{
// Handle each item.
Debug.WriteLine(JsonConvert.SerializeObject(item));
}
}
我正在使用 JSON 作为中间格式从旧的专有对象数据库格式迁移数据。对象被输出到一个 JSON 对象数组中,每个对象都有一个初始字段,给出原始对象的类型,后跟一个名为 Instance 的字段,该字段具有嵌套的原始对象。
我需要将它们流式传输,因为可能有数十万个 - 我不能只将整个 JSON 数组读入内存然后处理它。
所以 JSON 看起来像这样:
[
{
"Type": "Foo",
"Instance": {
// instance of Foo type
}
},
{
"Type": "Bar",
"Instance": {
// instance of Bar type
}
},
// tens or hundreds of thousands more objects...
]
使用 Json.NET,一次传入一个数组元素的最佳方法是什么,访问 "Type" 属性,然后将 "Instance" 反序列化为 .适当类型的网络对象?
编辑:虽然有一个关于读取大型 JSON 数组的类似问题,但该问题没有回答访问实例的具体问题。
汇总
的答案- Deserialize json array stream one item at a time
- Deserializing polymorphic json classes without type information using json.net,
首先,假设您有一个将类型名称映射到类型的自定义 SerializationBinder
(或类似的东西)。
接下来,您可以使用以下扩展方法枚举流式 JSON 数据中的顶级对象(遍历 进入 顶级数组):
public static class JsonExtensions
{
public static IEnumerable<JObject> WalkObjects(TextReader textReader)
{
using (JsonTextReader reader = new JsonTextReader(textReader))
{
while (reader.Read())
{
if (reader.TokenType == JsonToken.StartObject)
{
JObject obj = JObject.Load(reader);
if (obj != null)
{
yield return obj;
}
}
}
}
}
}
然后,假设您有一些 stream
用于读取您的 JSON 数据,您可以将 JSON 流式传输并逐一转换顶级数组元素以进行处理,如下所示:
SerializationBinder binder = new MyBinder(); // Your custom binder.
using (var stream = GetStream(json))
using (var reader = new StreamReader(stream, Encoding.Unicode))
{
var assemblyName = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
var items = from obj in JsonExtensions.WalkObjects(reader)
let jType = obj["Type"]
let jInstance = obj["Instance"]
where jType != null && jType.Type == JTokenType.String
where jInstance != null && jInstance.Type == JTokenType.Object
let type = binder.BindToType(assemblyName, (string)jType)
where type != null
select jInstance.ToObject(type); // Deserialize to bound type!
foreach (var item in items)
{
// Handle each item.
Debug.WriteLine(JsonConvert.SerializeObject(item));
}
}