簡體   English   中英

反序列化JSON以包含對C#中另一個反序列化對象的引用

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM