[英]Deserialize JSON to type containing reference to another deserialized object in C#
I have a following model: 我有以下模型:
public interface IEntity
{
string Id { get; }
}
public class EntityParent : IEntity
{
public string Id { get; }
public EntityChild EntityChild { get; }
[JsonConstructor]
public EntityParent(string id, EntityChild entityChild)
{
Id = id;
EntityChild = entityChild;
}
}
public class EntityChild : IEntity
{
public string Id { get; }
public int Age { get; }
[JsonConstructor]
public EntityChild(string id, int age)
{
Id = id;
Age = age;
}
}
Next I have some JSON that I need to deserialize to collections of the above types: 接下来,我有一些JSON需要反序列化为上述类型的集合:
{
"Children":
[
{
"Id" : "Billy",
"Age" : 42
}
],
"Parents" :
[
{
"Id" : "William",
"EntityChild" : "Billy"
}
]
}
Eventually I want to have a list of EntityChild
ren and a list of EntityParent
s that will (optionally) contain references to objects in the first list , or at least references to instances of EntityChild
. 最终,我想要一个
EntityChild
ren列表和EntityParent
列表,它们将(可选)包含对第一个列表中的对象的引用,或者至少包含对EntityChild
实例的EntityChild
。 I have attempted to write a custom JsonConverter
(I am using Newtonsoft.Json 9.0.1 NuGet package), where in the ReadJson()
method I am looking for a child with specific Id
, like so: 我试图编写一个自定义的
JsonConverter
(我正在使用Newtonsoft.Json 9.0.1 NuGet包),在其中,我在ReadJson()
方法中寻找一个具有特定Id
的孩子,如下所示:
public class ParentConverter<TEntity> : JsonConverter where TEntity : IEntity
{
private readonly IEnumerable<TEntity> _children;
public ParentConverter(IEnumerable<TEntity> children)
{
_children = children;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
JObject jObject = JObject.Load(reader);
TEntity target = _children.FirstOrDefault(d => d.Id == jObject["Id"].ToString());
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override bool CanConvert(Type objectType)
{
return typeof(TEntity).IsAssignableFrom(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Here's a simple test: 这是一个简单的测试:
public class JsonTest
{
const string Json = @"
{
""Children"": [
{
""Id"" : ""Billy"",
""Age"" : 42
}
],
""Parents"" : [
{
""Id"" : ""William"",
""EntityChild"" : ""Billy""
}
]
}";
public static void Main()
{
JObject jObject = JObject.Parse(Json);
var children =
JsonConvert.DeserializeObject<List<EntityChild>>(jObject["Children"].ToString());
var parents =
JsonConvert.DeserializeObject<List<EntityParent>>(jObject["Parents"].ToString(),
new ParentConverter<EntityChild>(children));
}
}
children
are deserialized properly, but parents
throw a JsonReaderException
when attempting to call JObject.Load(reader);
children
已正确反序列化,但是parents
JsonReaderException
在尝试调用JObject.Load(reader);
时抛出JsonReaderException
JObject.Load(reader);
in ReadJson()
, saying " Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '[0].EntityChild'. " 在
ReadJson()
中说:“ 从JsonReader读取JObject时出错。当前的JsonReader项不是对象:字符串。路径'[0] .EntityChild'。 ”
Does anyone know how I should go about it? 有人知道我应该怎么做吗? Thanks in advance.
提前致谢。
Edit: Updated the EntityChild
with extra property to emphasize that the property on EntityParent
has to be of EntityChild
type, and not a string . 编辑:更新了带有额外属性的
EntityChild
以强调EntityParent
上的属性必须为EntityChild
类型,而不是string 。
Entity parent should be as below: 实体父级应如下所示:
public class EntityParent : IEntity
{
public string Id { get; }
public string EntityChild { get; }
[JsonConstructor]
public EntityParent(string id, string entityChild)
{
Id = id;
EntityChild = entityChild;
}
}
And in main()
change as below: 并在
main()
中进行如下更改:
var parents = JsonConvert.DeserializeObject<List<EntityParent>>(jObject["Parents"].ToString());
and it works. 而且有效。
The following is sort of a workaround using LINQ, where I basically join the parent JObjects with children JObjects to build the parent and the child: 以下是使用LINQ的一种变通方法,在该方法中,我基本上将父JObject与子JObject连接在一起以构建父和子:
public static void Main()
{
JObject jObject = JObject.Parse(Json);
IEnumerable<EntityParent> parents =
from parent in jObject["Parents"]
join child in jObject["Children"] on parent["EntityChild"] equals child["Id"]
select
new EntityParent(
parent["Id"].ToString(),
new EntityChild(
child["Id"].ToString(),
child["Age"].ToObject<int>()));
}
If children list would exist already, then the join could be performed on that list instead, like so: 如果子列表已经存在,则可以在该列表上执行联接,如下所示:
public static void Main()
{
JObject jObject = JObject.Parse(Json);
var children =
JsonConvert.DeserializeObject<List<EntityChild>>(jObject["Children"].ToString());
IEnumerable<EntityParent> parents =
from parent in jObject["Parents"]
join child in children on parent["EntityChild"] equals child.Id
select new EntityParent(parent["Id"].ToString(), child);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.