好吧,如果您只需要一个额外的属性,一种简单的方法是将您的 JSON 解析为 JObject,使用 ToObject() 从 JObject 填充您的类,然后使用 SelectToken() 拉取在额外的属性中。
所以,假设你的班级看起来像这样:
class Person
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("age")]
public string Age { get; set; }
public string ProfilePicture { get; set; }
}
你可以这样做:
string json = @"
{
""name"" : ""Joe Shmoe"",
""age"" : 26,
""picture"":
{
""id"": 123456,
""data"":
{
""type"": ""jpg"",
""url"": ""http://www.someplace.com/mypicture.jpg""
}
}
}";
JObject jo = JObject.Parse(json);
Person p = jo.ToObject<Person>();
p.ProfilePicture = (string)jo.SelectToken("picture.data.url");
小提琴:https://dotnetfiddle.net/7gnJCK
如果您喜欢更花哨的解决方案,您可以自定义JsonConverter 以使JsonProperty 属性的行为与您描述的一样。转换器需要在类级别上运行,并结合上述技术使用一些反射来填充所有属性。以下是它在代码中的样子:
class JsonPathConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
object targetObj = Activator.CreateInstance(objectType);
foreach (PropertyInfo prop in objectType.GetProperties()
.Where(p => p.CanRead && p.CanWrite))
{
JsonPropertyAttribute att = prop.GetCustomAttributes(true)
.OfType<JsonPropertyAttribute>()
.FirstOrDefault();
string jsonPath = (att != null ? att.PropertyName : prop.Name);
JToken token = jo.SelectToken(jsonPath);
if (token != null && token.Type != JTokenType.Null)
{
object value = token.ToObject(prop.PropertyType, serializer);
prop.SetValue(targetObj, value, null);
}
}
return targetObj;
}
public override bool CanConvert(Type objectType)
{
// CanConvert is not called when [JsonConverter] attribute is used
return false;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
为了演示,我们假设 JSON 现在如下所示:
{
"name": "Joe Shmoe",
"age": 26,
"picture": {
"id": 123456,
"data": {
"type": "jpg",
"url": "http://www.someplace.com/mypicture.jpg"
}
},
"favorites": {
"movie": {
"title": "The Godfather",
"starring": "Marlon Brando",
"year": 1972
},
"color": "purple"
}
}
...除了之前的信息之外,您还对该人最喜欢的电影(标题和年份)和最喜欢的颜色感兴趣。您将首先使用[JsonConverter] 属性标记您的目标类以将其与自定义转换器关联,然后在每个属性上使用[JsonProperty] 属性,指定所需的属性路径(区分大小写)作为名称。目标属性也不必是原语——您可以像我在这里对Movie 所做的那样使用子类(注意不需要干预Favorites 类)。
[JsonConverter(typeof(JsonPathConverter))]
class Person
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("age")]
public int Age { get; set; }
[JsonProperty("picture.data.url")]
public string ProfilePicture { get; set; }
[JsonProperty("favorites.movie")]
public Movie FavoriteMovie { get; set; }
[JsonProperty("favorites.color")]
public string FavoriteColor { get; set; }
}
// Don't need to mark up these properties because they are covered by the
// property paths in the Person class
class Movie
{
public string Title { get; set; }
public int Year { get; set; }
}
有了所有的属性,你可以像往常一样反序列化,它应该“正常工作”:
Person p = JsonConvert.DeserializeObject<Person>(json);
小提琴:https://dotnetfiddle.net/Ljw32O