繁体   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