如果您只需要一个额外的属性,一种简单的方法是将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)
{
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; }
}
class Movie
{
public string Title { get; set; }
public int Year { get; set; }
}
有了所有的属性,您只需像平常一样反序列化,它就应该“正常工作”。
Person p = JsonConvert.DeserializeObject<Person>(json)
Fiddle: https://dotnetfiddle.net/Ljw32O