将JToken(或字符串)转换为给定的Type [英] Converting a JToken (or string) to a given Type

查看:941
本文介绍了将JToken(或字符串)转换为给定的Type的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL; DR版本

我有一个JToken类型的对象(但也可以是string),我需要将其转换为type变量中包含的Type:

I have a object of type JToken (but can also be a string) and I need to convert it into a Type contained in the type variable:

Type type = typeof(DateTime); /* can be any other Type like string, ulong etc */
var obj = jsonObject["date_joined"]; /* contains 2012-08-13T06:01:23Z+05:00 */
var result = Some_Way_To_Convert(type, obj);

上面的result应该是一个DateTime对象,其值在date_joined中给出.

The above result should be a DateTime object with the value given in date_joined.

全文

我在Windows Phone项目中同时使用RestSharp和Json.NET,在尝试反序列化REST API的JSON响应时遇到了麻烦.

I'm using both RestSharp and Json.NET in a Windows Phone project and I'm stuck while trying to deserialize JSON responses from a REST API.

我实际上要完成的工作是编写一个通用方法,该方法可以轻松地将JSON响应映射到我的CLR实体中,就像您已经可以使用RestSharp一样.唯一的问题是默认的RestSharp实现对我不起作用,并且它无法成功解析JSON,因为响应并不总是返回所有属性(我不返回REST服务器中null的字段).

What I'm actually trying to accomplish is to write a generic method that can easily map my JSON response into my CLR entities, much like you can do with RestSharp already. The only problem is that the default RestSharp implementation isn't working for me and it fails to successfully parse the JSON since the response doesn't always return all the properties (I don't return fields which are null from the REST server).

这就是为什么我决定使用Newtonsoft的Json.NET的原因,因为它具有更强大的Json反序列化引擎.不幸的是,它不支持RestSharp之类的模糊属性/字段名称(或者我还没有找到),因此当我使用诸如JsonConvert.DeserializeObject<User>(response.Content)之类的名称时,它也无法正确映射到我的CLR实体.

That's why I decided to use Newtonsoft's Json.NET since it has a much more powerful Json deserializing engine. Unfortunately, it doesn't support fuzzy property/field names like RestSharp (or I haven't found any), so it also doesn't map correctly to my CLR entities when I use something like say JsonConvert.DeserializeObject<User>(response.Content).

这就是我的Json的样子(实际上是一个例子):

Here's what my Json looks like (an example actually):

{
    "id" : 77239923,
    "username" : "UzEE",
    "email" : "uzee@email.net",
    "name" : "Uzair Sajid",
    "twitter_screen_name" : "UzEE",
    "join_date" : "2012-08-13T05:30:23Z05+00",
    "timezone" : 5.5,
    "access_token" : {
        "token" : "nkjanIUI8983nkSj)*#)(kjb@K",
        "scope" : [ "read", "write", "bake pies" ],
        "expires" : 57723
    },
    "friends" : [{
        "id" : 2347484",
        "name" : "Bruce Wayne"
    },
    {
        "id" : 996236,
        "name" : "Clark Kent"
    }]
}

这是我的CLR实体的示例:

And here's an example of my CLR entities:

class AccessToken 
{
    public string Token { get; set; }
    public int Expires { get; set; }
    public string[] Scope { get; set; }
    public string Secret { get; set; } /* may not always be returned */
}

class User
{
    public ulong Id { get; set; }
    public string UserName { get; set; }
    public string Email { get; set; }
    public string Name { get; set; }
    public string TwitterScreenName { get; set; }
    public DateTime JoinDate { get; set; }
    public float Timezone { get; set; }
    public bool IsOnline { get; set; } /* another field that might be blank e.g. */

    public AccessToken AccessToken { get; set; }

    public List<User> Friends { get; set; }
}

我想要的是一种简单的方法,将上述JSON解析为给定的CLR对象.我查看了RestSharp源代码,并看到了JsonDeserializer代码,并且已经能够在JObject上编写通用扩展方法DeserializeResponse<T>,该方法应该返回类型为T的对象.预期用途是这样的:

What I want is a simple way to parse the above JSON into the given CLR objects. I've looked around the RestSharp source code and have seen the JsonDeserializer code and I've been able to write a generic extension method DeserializeResponse<T> on JObject that should return a an object of type T. The intended use is something like this:

var user = JObject.Parse(response.Content).DeserializeResponse<User>();

上述方法应该解析给定的Json Response到User实体对象.这是我在DeserializeResponse<User>扩展方法(基于RestSharp代码)中正在执行的操作的实际代码片段:

The above method should parse the given Json Response to a User entity object. Here's an actual code snippet of what I'm doing in the DeserializeResponse<User> extension method (its based on RestSharp code):

public static T DeserializeResponse<T>(this JObject obj) where T : new()
{
    T result = new T();
    var props = typeof(T).GetProperties().Where(p => p.CanWrite).ToList();
    var objectDictionary = obj as IDictionary<string, JToken>;

    foreach (var prop in props)
    {
        var name = prop.Name.GetNameVariants(CultureInfo.CurrentCulture).FirstOrDefault(n => objectDictionary.ContainsKey(n));
        var value = name != null ? obj[name] : null;

        if (value == null) continue;

        var type = prop.PropertyType;

        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            type = type.GetGenericArguments()[0];
        }

        // This is a problem. I need a way to convert JToken value into an object of Type type
        prop.SetValue(result, ConvertValue(type, value), null); 
    }

    return result;
}

我猜想转换应该是一件非常简单的事情,因为它是一项琐碎的任务.但是我已经搜索了很长一段时间,但仍然没有找到通过Json.NET做到这一点的方法(而且,老实说,该文档虽然可以理解,但缺少一些示例).

I'm guessing that the conversion should be a really straightforward thing to do since its a trivial task. But I've been searching for a quite a while now and still haven't found a way to do it via Json.NET (and lets be honest, the documentation is kinda though to understand and lacks some examples).

我们将不胜感激.

推荐答案

现在有一个ToObject方法.

There is a ToObject method now.

var obj = jsonObject["date_joined"];
var result = obj.ToObject<DateTime>();

它还可以与任何复杂类型一起使用,并遵守JsonPropertyAttribute规则

It also works with any complex type, and obey to JsonPropertyAttribute rules

var result = obj.ToObject<MyClass>();

public class MyClass 
{ 
    [JsonProperty("date_field")]
    public DateTime MyDate {get;set;}
}

这篇关于将JToken(或字符串)转换为给定的Type的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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