2016-07-13 155 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