有没有一种方法可以反序列化我的JSON,而不需要为每个项使用包装器类



我正在使用JSON.NET开发一个与第三方REST API接口的ASP.NET应用程序。API以以下格式返回JSON:

[
    {
        user: {
            id: 12345,
            first_name: "John",
            last_name: "Smith",
            created_at: "11/12/13Z00:00:00"
        }
    },
    {
        user: {
            id: 12346,
            first_name: "Bob",
            last_name: "Adams",
            created_at: "12/12/13Z00:00:00"
        }
    }
]

user字段是多余的,但我无法控制API,因此我必须使用它。我目前正在使用以下代码来反序列化JSON:

// Deserialize
var responseBody = JsonConvert.DeserializeObject<IEnumerable<UserWrapper>>(responseString);
// Access Properties
foreach (var userWrapper in responseBody)
{
    var firstName = userWrapper.User.FirstName
}
// Model classes
public class UserWrapper
{
    [JsonProperty(PropertyName = "user")]
    public User User { get; set; }
}
public class User
{
    [JsonProperty(PropertyName = "id")]
    public string ID { get; set; }
    [JsonProperty(PropertyName = "first_name")]
    public string FirstName { get; set; }
    [JsonProperty(PropertyName = "last_name")]
    public string LastName { get; set; }
    [JsonProperty(PropertyName = "created_at")]
    public DateTime CreatedAt { get; set; }
}

拥有包装器类有点难看。所以我的问题是:

有没有一种方法可以使用JSON.NET消除包装类

是的,您可以通过为User类创建一个自定义转换器并在反序列化过程中使用它来实现这一点。转换器代码可能看起来像这样:

class UserConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(User));
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject wrapper = JObject.Load(reader);
        return wrapper["user"].ToObject<User>();
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteStartObject();
        writer.WritePropertyName("user");
        writer.WriteRawValue(JsonConvert.SerializeObject(value));
        writer.WriteEndObject();
    }
}

保持User类与您定义的完全一样(使用所有JsonProperty装饰)。然后,您可以反序列化JSON并访问如下属性:

var users = JsonConvert.DeserializeObject<List<User>>(responseString, new UserConverter());
foreach (var user in users)
{
    var firstName = user.FirstName
    // etc...
}

UserWrapper类不再需要,可以删除。

编辑

重要提示:如果使用[JsonConverter]属性装饰User类,则上述解决方案将不起作用。这是因为编写的自定义转换器使用序列化程序的第二个副本来处理User反序列化,一旦我们降低了一个级别以获得真实的用户数据。如果对类进行修饰,那么序列化程序的所有副本都将尝试使用转换器,最终会出现自引用循环。

如果您更愿意使用[JsonConverter]属性,那么自定义转换器类将不得不手动处理User类的所有属性的反序列化。采用这种方法,代码会变成这样:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    JObject wrapper = JObject.Load(reader);
    JToken user = wrapper["user"];
    return new User
    {
        ID = user["id"].Value<string>(),
        FirstName = user["first_name"].Value<string>(),
        LastName = user["last_name"].Value<string>(),
        CreatedAt = user["created_at"].Value<DateTime>()
    };
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    User user = (User)value;
    writer.WriteStartObject();
    writer.WritePropertyName("user");
    writer.WriteStartObject();
    writer.WritePropertyName("id");
    writer.WriteValue(user.ID);
    writer.WritePropertyName("first_name");
    writer.WriteValue(user.FirstName);
    writer.WritePropertyName("last_name");
    writer.WriteValue(user.LastName);
    writer.WritePropertyName("created_at");
    writer.WriteValue(user.CreatedAt);
    writer.WriteEndObject();
    writer.WriteEndObject();
}

这种方法的明显问题是,您牺牲了一点可维护性:如果您向User类添加了更多属性,则必须记住更改UserConverter以匹配。

相关内容

  • 没有找到相关文章

最新更新