gpt4 book ai didi

c# - 我可以在属性中指定路径以将类中的属性映射到 JSON 中的子属性吗?

转载 作者:太空宇宙 更新时间:2023-11-03 15:00:28 25 4
gpt4 key购买 nike

有一些代码(我无法更改)使用 Newtonsoft.Json 的 DeserializeObject<T>(strJSONData) 从网络请求中获取数据并将其转换为类对象(我可以更改类)。通过使用 [DataMember(Name = "raw_property_name")] 装饰我的类属性,我可以将原始 JSON 数据映射到我的类中的正确属性。有没有办法可以将 JSON 复杂对象的子属性映射到简单属性?这是一个例子:

{
"picture":
{
"id": 123456,
"data":
{
"type": "jpg",
"url": "http://www.someplace.com/mypicture.jpg"
}
}
}

除了 URL,我不关心图片对象的任何其他部分,因此不想在我的 C# 类中设置复杂的对象。我真的只是想要这样的东西:

[DataMember(Name = "picture.data.url")]
public string ProfilePicture { get; set; }

这可能吗?

最佳答案

好吧,如果您只需要一个额外的属性,一个简单的方法是将您的 JSON 解析为 JObject,使用 ToObject()JObject,然后使用 SelectToken() 拉入额外的属性。

因此,假设您的类(class)看起来像这样:

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");

fiddle :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);

fiddle :https://dotnetfiddle.net/Ljw32O

关于c# - 我可以在属性中指定路径以将类中的属性映射到 JSON 中的子属性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46444462/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com