75

TL;DR バージョン

タイプのオブジェクトがありますJToken(ただし、 の場合もあります)。それを変数stringに含まれるタイプに変換する必要があります。type

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

フルストーリー

Windows Phone プロジェクトで RestSharp と Json.NET の両方を使用していますが、REST API からの JSON 応答を逆シリアル化しようとしてスタックしています。

私が実際に達成しようとしているのは、RestSharp で既にできるように、JSON 応答を CLR エンティティに簡単にマップできる汎用メソッドを作成することです。null唯一の問題は、デフォルトの RestSharp 実装が機能せず、応答がすべてのプロパティを返すとは限らない ( REST サーバーからのフィールドを返さない) ため、JSON を正常に解析できないことです。

そのため、はるかに強力な Json デシリアライズ エンジンを備えている Newtonsoft の Json.NET を使用することにしました。残念ながら、RestSharp のようなあいまいなプロパティ/フィールド名をサポートしていない (または見つからなかった) ため、 say のようなものを使用すると、CLR エンティティにも正しくマップされませんJsonConvert.DeserializeObject<User>(response.Content)

これが私のJsonの外観です(実際の例):

{
    "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 エンティティの例です。

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書くことができました。使用目的は次のようなものです。DeserializeResponse<T>JObjectT

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

上記のメソッドは、指定された Json レスポンスを User エンティティ オブジェクトに解析する必要があります。これは、拡張メソッドで行っていることの実際のコード スニペットですDeserializeResponse<User>(RestSharp コードに基づいています)。

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 を介してそれを行う方法をまだ見つけていません (正直に言うと、ドキュメントは理解するのにちょっと手間がかかり、いくつかの例が欠けています)。

どんな助けでも本当に感謝します。

4

4 に答える 4

135

現在、ToObject メソッドがあります。

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

また、任意の複合型で機能し、JsonPropertyAttribute 規則に従います。

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

public class MyClass 
{ 
    [JsonProperty("date_field")]
    public DateTime MyDate {get;set;}
}
于 2013-12-05T18:20:31.660 に答える
24
System.Convert.ChangeType(jtoken.ToString(), targetType);

また

JsonConvert.DeserializeObject(jtoken.ToString(), targetType);

- 編集 -

Uzair、ここにそれらが機能することを示すための完全な例があります

string json = @"{
        ""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""
        }]
    }";

var obj = (JObject)JsonConvert.DeserializeObject(json);
Type type = typeof(int);
var i1 = System.Convert.ChangeType(obj["id"].ToString(), type);
var i2 = JsonConvert.DeserializeObject(obj["id"].ToString(), type);
于 2012-08-13T11:50:32.243 に答える
1
var i2 = JsonConvert.DeserializeObject(obj["id"].ToString(), type);

最初の引数の周りに引用符がないため、解析例外がスローされます (私は思います)。引用符を追加して動作させました:

var i2 = JsonConvert.DeserializeObject("\"" + obj["id"].ToString() + "\"", type);
于 2013-01-30T14:19:57.183 に答える
1

WebAPI の以下のメソッドを使用して変換できました。

[HttpPost]
public HttpResponseMessage Post(dynamic item) // Passing parameter as dynamic
{
JArray itemArray = item["Region"]; // You need to add JSON.NET library
JObject obj = itemArray[0] as JObject;  // Converting from JArray to JObject
Region objRegion = obj.ToObject<Region>(); // Converting to Region object
}
于 2013-12-17T22:58:32.377 に答える