我有一个非常不受欢迎的情况,需要我反序列化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
以上类的最佳方法是什么?
答案 0 :(得分:6)
您可以创建自定义JsonConverter
来序列化/反序列化Role[]
。然后,您可以使用Roles
装饰JsonConverterAttribute
属性,如下所示:
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();
}
}
答案 1 :(得分: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 :(得分: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);