[英]Deserialize JSON to type containing reference to another deserialized object in C#
我有以下模型:
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;
}
}
接下來,我有一些JSON需要反序列化為上述類型的集合:
{
"Children":
[
{
"Id" : "Billy",
"Age" : 42
}
],
"Parents" :
[
{
"Id" : "William",
"EntityChild" : "Billy"
}
]
}
最終,我想要一個EntityChild
ren列表和EntityParent
列表,它們將(可選)包含對第一個列表中的對象的引用,或者至少包含對EntityChild
實例的EntityChild
。 我試圖編寫一個自定義的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();
}
}
這是一個簡單的測試:
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
已正確反序列化,但是parents
JsonReaderException
在嘗試調用JObject.Load(reader);
時拋出JsonReaderException
JObject.Load(reader);
在ReadJson()
中說:“ 從JsonReader讀取JObject時出錯。當前的JsonReader項不是對象:字符串。路徑'[0] .EntityChild'。 ”
有人知道我應該怎么做嗎? 提前致謝。
編輯:更新了帶有額外屬性的EntityChild
以強調EntityParent
上的屬性必須為EntityChild
類型,而不是string 。
實體父級應如下所示:
public class EntityParent : IEntity
{
public string Id { get; }
public string EntityChild { get; }
[JsonConstructor]
public EntityParent(string id, string entityChild)
{
Id = id;
EntityChild = entityChild;
}
}
並在main()
中進行如下更改:
var parents = JsonConvert.DeserializeObject<List<EntityParent>>(jObject["Parents"].ToString());
而且有效。
以下是使用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>()));
}
如果子列表已經存在,則可以在該列表上執行聯接,如下所示:
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.