1. ホーム
  2. c#

JToken(または文字列)を与えられたTypeに変換する

2023-11-27 17:30:57

質問

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エンティティに簡単にマッピングできる汎用メソッドを記述することです。唯一の問題は、デフォルトのRestSharp実装が私のために動作していないことで、それはJSONを正常にパースするのに失敗します。 null であるフィールドをRESTサーバーから返さない)。

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

私のJsonはこんな感じです(実際には例です)。

{
    "id" : 77239923,
    "username" : "UzEE",
    "email" : "[email protected]",
    "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>JObject という型のオブジェクトを返すはずです。 T . 意図した使い方は次のようなものです。

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

上記のメソッドは、与えられたJson Responseをパースして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経由でそれを行う方法をまだ見つけていません(そして、正直に言うと、ドキュメントは理解するのが難しく、いくつかの例も欠けています)。

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

どのように解決するのですか?

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;}
}