問題描述
有一些代碼(我無法更改)使用 Newtonsoft.Json 的 DeserializeObject<T>(strJSONData)
從 Web 請求中獲取數據并將其轉換為類對象(我可以換班).通過使用 [DataMember(Name = "raw_property_name")]
裝飾我的類屬性,我可以將原始 JSON 數據映射到我的類中的正確屬性.有沒有辦法可以將 JSON 復雜對象的子屬性映射到簡單屬性?這是一個例子:
There is some code (which I can't change) that uses Newtonsoft.Json's DeserializeObject<T>(strJSONData)
to take data from a web request and convert it to a class object (I can change the class). By decorating my class properties with [DataMember(Name = "raw_property_name")]
I can map the raw JSON data to the correct property in my class. Is there a way I can map the child property of a JSON complex object to a simple property? Here's an example:
{
"picture":
{
"id": 123456,
"data":
{
"type": "jpg",
"url": "http://www.someplace.com/mypicture.jpg"
}
}
}
除了 URL 之外,我不關心圖片對象的任何其余部分,因此不想在我的 C# 類中設置復雜的對象.我真的只是想要這樣的東西:
I don't care about any of the rest of the picture object except for URL, and so don't want to setup a complex object in my C# class. I really just want something like:
[DataMember(Name = "picture.data.url")]
public string ProfilePicture { get; set; }
這可能嗎?
推薦答案
好吧,如果你只需要一個額外的屬性,一個簡單的方法是將你的 JSON 解析為 JObject
,使用 ToObject()
從 JObject
填充您的類,然后使用 SelectToken()
拉入額外的屬性.
Well, if you just need a single extra property, one simple approach is to parse your JSON to a JObject
, use ToObject()
to populate your class from the JObject
, and then use SelectToken()
to pull in the extra property.
所以,假設你的班級看起來像這樣:
So, assuming your class looked something like this:
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
屬性的行為與您描述的一樣.轉換器需要在類級別上運行,并結合上述技術使用一些反射來填充所有屬性.以下是它在代碼中的樣子:
If you prefer a more fancy solution, you could make a custom JsonConverter
to enable the JsonProperty
attribute to behave like you describe. The converter would need to operate at the class level and use some reflection combined with the above technique to populate all the properties. Here is what it might look like in code:
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 現在如下所示:
To demonstrate, let's assume the JSON now looks like the following:
{
"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
類).
...and you are interested in the person's favorite movie (title and year) and favorite color in addition to the information from before. You would first mark your target class with a [JsonConverter]
attribute to associate it with the custom converter, then use [JsonProperty]
attributes on each property, specifying the desired property path (case sensitive) as the name. The target properties don't have to be primitives either-- you can use a child class like I did here with Movie
(and notice there's no intervening Favorites
class required).
[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; }
}
有了所有屬性,你就可以像往常一樣反序列化,它應該正常工作":
With all the attributes in place, you can just deserialize as normal and it should "just work":
Person p = JsonConvert.DeserializeObject<Person>(json);
小提琴:https://dotnetfiddle.net/Ljw32O
這篇關于我可以在屬性中指定路徑以將我的類中的屬性映射到我的 JSON 中的子屬性嗎?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!