2016-07-13 30 views
1

我有以下模型:反序列化JSON来键入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 s,它将(可选)包含对第一个列表中的对象的引用,或者至少包含对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试图调用JObject.Load(reader);ReadJson()时抛出JsonReaderException,称“从JsonReader读取JObject时出错。当前的JsonReader项目不是一个对象:String。路径'[0] .EntityChild'。

有谁知道我应该如何去了解它在此先感谢

编辑:?更新了EntityChild有额外的属性强调的是,在EntityParent的财产必须是EntityChild类型,,而不是一个字符串

+0

谁设计了JSON结构?这很奇怪 –

+0

@SirRufo不幸的是,它超出了我的手:(:(这不是我);)。 – Caleb9

回答

0

以下是排序使用LINQ,在这里我基本上是与孩子JObjects加入父JObjects建立家长和孩子的一种解决方法:

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); 
    } 
2

实体家长应如下:

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()); 

和它的作品。

+0

是的,但重点是具有EntityChild类型的属性,所以在模型中我可以使用自定义类型而不是字符串。这个例子是故意简单的,但在真实场景中,除了Id之外,我还会在EntityChild上拥有其他属性,然后这种解决方案就不够了。 – Caleb9