How to deserialize Newtonsoft Json.NET references to separate, individual instances(如何反序列化 Newtonsoft Json.NET 对单独实例的引用)
问题描述
我有一段如下所示的 JSON:
I have a piece of JSON that looks like this:
[
{
"$id": "1",
"Name": "James",
"BirthDate": "1983-03-08T00:00Z",
"LastModified": "2012-03-21T05:40Z"
},
{
"$ref": "1"
}
]
从 $ref 可以看出,这个 JSON 数组包含两次相同的 Person (James).第二次是对第一次的引用.
As you can tell by the $ref, this JSON array contains the same Person (James), twice. The second time is a reference to the first.
我想知道是否有办法将这个 JSON 反序列化成一个包含詹姆斯人的两个副本的对象.
I am wondering if there is a way to deserialize this JSON into an object that contains two copies of the James person.
目前,我正在使用这个:
Currently, I'm using this:
var jsonSerializerSettings = new JsonSerializerSettings()
{
PreserveReferencesHandling = PreserveReferencesHandling.None,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var deserializedPersons = JsonConvert.DeserializeObject<List<Person>>(json, jsonSerializerSettings);
但这只是给了我一个具有相同 Person 实例的数组,两次:
But this just gives me an array with the same instance of the Person, twice:
object.ReferenceEquals(deserializedPersons[0], deserializedPersons[1]) // Evaluates to true
我找到了一个我不满意的解决方法,它只是反序列化 JSON 字符串,然后使用上面的 jsonSerializerSettings 对其进行序列化,这将复制 JSON 中的人,然后再次对其进行反序列化.这会导致我们正在使用的大型对象严重减速.
I've found a workaround I am unhappy with which is simply deserializing the JSON string, then serializing it using the jsonSerializerSettings above, which will duplicate the person in the JSON, then deserializing it again. This is causing major slowdowns for the large objects we are using.
注意:我知道我可以更改从中检索此 JSON 的 API 以复制数据,但在发送响应 JSON 时保留引用可以节省大量空间电线.
Note: I know I could change the API that I retrieve this JSON from to duplicate the data, but preserving the references saves substantial space when sending the response JSON over the wire.
推荐答案
你可以使用 自定义参考解析器.例如,假设 Name
是您的对象的主键",这应该可以工作.当然,您可能想让它更通用.
You could use a custom reference resolver. For example, assuming Name
is the "primary key" for your objects, this should work. Of course, you may want to make it more generic.
public class PersonReferenceResolver : IReferenceResolver
{
private readonly IDictionary<string, Person> _objects =
new Dictionary<string, Person>();
public object ResolveReference(object context, string reference)
{
Person p;
if (_objects.TryGetValue(reference, out p))
{
//This is the "clever" bit. Instead of returning the found object
//we just return a copy of it.
//May be better to clone your class here...
return new Person
{
Name = p.Name,
BirthDate = p.BirthDate,
LastModified = p.LastModified
};
}
return null;
}
public string GetReference(object context, object value)
{
Person p = (Person)value;
_objects[p.Name] = p;
return p.Name;
}
public bool IsReferenced(object context, object value)
{
Person p = (Person)value;
return _objects.ContainsKey(p.Name);
}
public void AddReference(object context, string reference, object value)
{
_objects[reference] = (Person)value;
}
}
现在你像这样反序列化:
Now you deserialise like this:
var jsonSerializerSettings = new JsonSerializerSettings()
{
ReferenceResolver = new PersonReferenceResolver()
};
var deserializedPersons = JsonConvert.DeserializeObject<List<Person>>(
json, jsonSerializerSettings);
<小时>
我很无聊,所以我做了一个通用版本:
I was bored so I made a generic version:
public class GenericResolver<TEntity> : IReferenceResolver
where TEntity : ICloneable, new()
{
private readonly IDictionary<string, TEntity> _objects = new Dictionary<string, TEntity>();
private readonly Func<TEntity, string> _keyReader;
public GenericResolver(Func<TEntity, string> keyReader)
{
_keyReader = keyReader;
}
public object ResolveReference(object context, string reference)
{
TEntity o;
if (_objects.TryGetValue(reference, out o))
{
return o.Clone();
}
return null;
}
public string GetReference(object context, object value)
{
var o = (TEntity)value;
var key = _keyReader(o);
_objects[key] = o;
return key;
}
public bool IsReferenced(object context, object value)
{
var o = (TEntity)value;
return _objects.ContainsKey(_keyReader(o));
}
public void AddReference(object context, string reference, object value)
{
if(value is TEntity)
_objects[reference] = (TEntity)value;
}
}
稍微新的用法:
var jsonSerializerSettings = new JsonSerializerSettings()
{
//Now we need to specify the type and how to get the object's key
ReferenceResolver = new GenericResolver<Person>(p => p.Name)
};
var deserializedPersons = JsonConvert.DeserializeObject<List<Person>>(
json, jsonSerializerSettings);
这篇关于如何反序列化 Newtonsoft Json.NET 对单独实例的引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何反序列化 Newtonsoft Json.NET 对单独实例的引用
基础教程推荐
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- MS Visual Studio .NET 的替代品 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01