2013-07-19 120 views
4

我有一個非常不受歡迎的情況,它要求我反序列化JSON.NET中值爲字段名的JSON。假設我有以下的JSON這是非常正確的結構:反序列化JSON.NET中值爲字段名稱的JSON

{ 
    "name": "tugberk", 
    "roles": [ 
     { "id": "1", "name": "admin" }, 
     { "id": "2", "name": "guest" } 
    ] 
} 

它很容易與JSON.NET反序列化這CLR對象:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var camelCaseSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }; 

     var text = File.ReadAllText("user_normal.txt"); 
     var obj = JsonConvert.DeserializeObject<User>(text, camelCaseSettings); 
    } 
} 

public class User 
{ 
    public string Name { get; set; } 
    public Role[] Roles { get; set; } 
} 

public class Role 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

然而,在我目前的情況下,我具有以下可怕JSON其等同於上述的在JSON值方面:

{ 
    "name": "tugberk", 
    "roles": { 
     "1": { "name": "admin" }, 
     "2": { "name": "guest" } 
    } 
} 

正如你可以看到,roles字段不是陣列;它是一個包含其他值作爲對象的唯一鍵作爲其字段名稱的對象(這太可怕了)。使用JSON.NET將此JSON反序列化到User類的最佳方法是什麼?

回答

6

您可以創建一個自定義JsonConverter,該序列化/反序列化Role[]。然後,您可以用JsonConverterAttribute這樣的裝點您的Roles屬性:

public class User 
{ 
    public string Name { get; set; } 
    [JsonConverter(typeof(RolesConverter))] 
    public Role[] Roles { get; set; } 
} 

在你的轉換器類,你可以閱讀的對象,並返回一個數組來代替。你的轉換器類可能是這樣的:

class RolesConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(Role[]); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     // deserialize as object 
     var roles = serializer.Deserialize<JObject>(reader); 
     var result = new List<Role>(); 

     // create an array out of the properties 
     foreach (JProperty property in roles.Properties()) 
     { 
      var role = property.Value.ToObject<Role>(); 
      role.Id = int.Parse(property.Name); 
      result.Add(role); 
     } 

     return result.ToArray(); 
    } 


    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 
2

嗯,你可以嘗試:

dynamic jObject = JObject.Parse(text); 
List<User> users = new List<User>(); 

foreach(dynamic dUser in jObject) 
{ 
    List<Role> roles = new List<Role>(); 
    User user = new User(); 
    user.Name = dUser.name; 
    foreach(PropertyInfo info in dUser.GetType().GetProperties()) 
    { 
     Role role = new Role(); 
     role.Id = info.Name; 
     role.Name = dUser[info.Name].name; 
     roles.Ad(role); 
    } 
    user.Roles = roles.ToArray(); 
} 
2

有提供給你幾個選擇。您可以自定義JsonConverter並手動序列化它。由於本FERO提供基於此答案寫作的時候,我給你一個選擇,需要兩個代理類:

public class JsonUser 
{ 
    public string Name { get; set; } 
    public Dictionary<int, JsonRole> Roles { get; set; } 
} 

public class JsonRole 
{ 
    public string Name { get; set; } 
} 

而在你Role類:

public static implicit operator User(JsonUser user) 
{ 
    return new User 
     { 
      Name = user.Name, 
      Roles = user.Roles 
         .Select(kvp => new Role { Id = kvp.Key, Name = kvp.Value.Name}) 
         .ToArray() 
     }; 
} 

可使用這樣的:

User jsonUser = JsonConvert.DeserializeObject<JsonUser>(json); 

現在,這是在創建一箇中間對象爲代價的,可能不適合大多數情況下。

爲了完整起見,我會包含我的版本JsonConverter解決方案:

public class UserRolesConverter : JsonConverter 
{ 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof (Role[]); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     return serializer.Deserialize<JObject>(reader) 
         .Properties() 
         .Select(p => new Role 
          { 
           Id = Int32.Parse(p.Name), 
           Name = (string) p.Value["name"] 
          }) 
         .ToArray(); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class User 
{ 
    public string Name { get; set; } 
    [JsonConverter(typeof(UserRolesConverter))] 
    public Role[] Roles { get; set; } 
} 

var jsonUser = JsonConvert.DeserializeObject<User>(json);