2013-07-19 1 views
4

값이 JSON.NET 인 필드 이름 인 JSON을 비 직렬화해야하는 매우 바람직하지 않은 상황이 있습니다. 나는 나의 현재의 경우,값이 JSON.NET에서 필드 이름 인 JSON을 비 직렬화

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

그러나 : 그것은 CLR 개체에 JSON.NET 이것을 역 직렬화하는 것은 매우 쉽다

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

: 나는 매우 적절하게 구성되어 다음과 같은 JSON을 가지고 있다고 가정 , roles 필드 배열이 아닌

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

시피; 값의 관점에서 상술 JSON 동등 다음 끔찍한 JSON을 그것은 필드 이름 (그것은 끔찍한)으로 고유 한 키를 가진 객체로서 다른 값을 포함하는 객체입니다. 이 JSON을 JSON.NET에서 User 클래스 이상으로 역 직렬화하는 가장 좋은 방법은 무엇입니까?

답변

6

Role[]을 serialize/deserialize하는 사용자 지정 JsonConverter을 만들 수 있습니다. 그런 다음이 같은 JsonConverterAttributeRoles 속성을 장식 할 수 있습니다 : 당신의 계산기 클래스에서

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을 사용하여 수동으로 직렬화 할 수 있습니다.

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

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

그리고 당신의 Role 클래스 :이 FERO이 기반으로 답변을 제공 글을 쓰는 시점으로 때문에, 나는이 개 대리 수업이 필요한 당신에게 대안을주지

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

이제는 중간 개체를 만드는 비용으로 수행되며 대부분의 경우 적합하지 않을 수 있습니다.

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); 
: 완성도를 위해서

, 나는 JsonConverter 솔루션의 내 버전을 포함합니다
관련 문제