如何在C#反序列化时将非扁平JSON映射到扁平类?
非扁平JSON反序列化为扁平C#类的实现方法
先拿你提到的嵌套JSON示例来说:
{
"id": "123",
"data": {
"username": "jason",
"email": "jason@example.com",
"age": 30
}
}
我们要把它直接转成这样的扁平User类:
public class User { public string Id { get; set; } public string Username { get; set; } public string Email { get; set; } public int Age { get; set; } }
一、用.NET内置的System.Text.Json实现
方法1:自定义JsonConverter
写一个转换器手动映射嵌套属性,适合需要复用的场景:
public class UserConverter : JsonConverter<User> { public override User Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var jsonDoc = JsonDocument.ParseValue(ref reader); var root = jsonDoc.RootElement; return new User { Id = root.GetProperty("id").GetString(), Username = root.GetProperty("data").GetProperty("username").GetString(), Email = root.GetProperty("data").GetProperty("email").GetString(), Age = root.GetProperty("data").GetProperty("age").GetInt32() }; } // 如果需要把User序列化回原JSON结构,实现下面的Write方法即可 public override void Write(Utf8JsonWriter writer, User value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteString("id", value.Id); writer.WriteStartObject("data"); writer.WriteString("username", value.Username); writer.WriteString("email", value.Email); writer.WriteNumber("age", value.Age); writer.WriteEndObject(); writer.WriteEndObject(); } }
使用转换器反序列化:
var json = "{\"id\":\"123\",\"data\":{\"username\":\"jason\",\"email\":\"jason@example.com\",\"age\":30}}"; var options = new JsonSerializerOptions(); options.Converters.Add(new UserConverter()); var user = JsonSerializer.Deserialize<User>(json, options);
方法2:LINQ to JSON直接映射
如果只是单次使用,不用写转换器,直接解析后手动赋值更省事:
var jsonDoc = JsonDocument.Parse(json); var user = new User { Id = jsonDoc.RootElement.GetProperty("id").GetString(), Username = jsonDoc.RootElement.GetProperty("data").GetProperty("username").GetString(), Email = jsonDoc.RootElement.GetProperty("data").GetProperty("email").GetString(), Age = jsonDoc.RootElement.GetProperty("data").GetProperty("age").GetInt32() };
二、用Newtonsoft.Json(Json.NET)实现
Newtonsoft的方案更简洁,直接给属性标注路径就行:
方法1:JsonProperty指定嵌套路径
不用写转换器,直接在User类的属性上标注JsonProperty,指定JSON里的嵌套路径:
public class User { [JsonProperty("id")] public string Id { get; set; } [JsonProperty("data.username")] public string Username { get; set; } [JsonProperty("data.email")] public string Email { get; set; } [JsonProperty("data.age")] public int Age { get; set; } }
然后直接反序列化:
var json = "{\"id\":\"123\",\"data\":{\"username\":\"jason\",\"email\":\"jason@example.com\",\"age\":30}}"; var user = JsonConvert.DeserializeObject<User>(json);
方法2:自定义JsonConverter(按需使用)
如果需要更复杂的逻辑,也可以写转换器:
public class UserConverter : JsonConverter<User> { public override User ReadJson(JsonReader reader, Type objectType, User existingValue, bool hasExistingValue, JsonSerializer serializer) { var jo = JObject.Load(reader); return new User { Id = jo["id"].ToString(), Username = jo["data"]["username"].ToString(), Email = jo["data"]["email"].ToString(), Age = (int)jo["data"]["age"] }; } // 序列化回原结构的逻辑 public override void WriteJson(JsonWriter writer, User value, JsonSerializer serializer) { var jo = new JObject(); jo["id"] = value.Id; var dataObj = new JObject(); dataObj["username"] = value.Username; dataObj["email"] = value.Email; dataObj["age"] = value.Age; jo["data"] = dataObj; jo.WriteTo(writer); } }
使用转换器的代码:
var settings = new JsonSerializerSettings(); settings.Converters.Add(new UserConverter()); var user = JsonConvert.DeserializeObject<User>(json, settings);
内容的提问来源于stack exchange,提问作者Jason Steinshouer
相关产品推荐
相关产品推荐

