我可以在属性指定的路径在我的类中的属性映射到我的JSON孩子的财产? [英] Can I specify a path in an attribute to map a property in my class to a child property in my JSON?

查看:132
本文介绍了我可以在属性指定的路径在我的类中的属性映射到我的JSON孩子的财产?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一些code(我不能改变),使用Newtonsoft.Json的 DeserializeObject< T>(strJSONData)从Web请求获取数据并将其转换为一个类对象(Ⅰ可以改变类)。通过与装饰我的类属性[数据成员(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

如果您preFER一个更看中的解决方案,你可以做一个自定义的 JsonConverter 启用 JsonProperty 属性表现像你描述。该转换器将需要在类级别操作和使用一些反思与上述技术来填充的所有属性结合起来。下面是它可能看起来像在code:

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] 属性的每个属性,指定作为名称所需的属性路径(区分大小写)。目标属性没有被像元我电影在这里所做的either--你可以使用一个子类(并注意有没有干预收藏所需的类)。

...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孩子的财产?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆