4

私はWinRT (C#) 用の .NET を使用しています。JSON 文字列を に逆シリアル化したいのですDictionary<string, object>が、辞書の値を後で実際の型に変換できます。JSON 文字列にはオブジェクト階層を含めることができ、子オブジェクトも含めたいと思いDictionary<string, object>ます。

処理できるはずの JSON のサンプルを次に示します。

{
  "Name":"John Smith",
  "Age":42,
  "Parent":
  {
    "Name":"Brian Smith",
    "Age":65,
    "Parent":
    {
       "Name":"James Smith",
       "Age":87,
    }
  }
}

私はDataContractJsonSerializerを次のようにしてみました:

using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
    DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings();
    settings.UseSimpleDictionaryFormat = true;

    DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Dictionary<string, object>), settings);
    Dictionary<string, object> results = (Dictionary<string, object>)serializer.ReadObject(ms);
}

これは実際には最初のレベルでは問題なく機能しますが、「親」は にキャストできない単なるオブジェクトですDictionary<string, object>

Dictionary<string, object> parent = (Dictionary<string, object>)results["Parent"];
Cannot cast 'results["Parent"]' (which has an actual type of 'object') to 'System.Collections.Generic.Dictionary<string,object>'

次に、Json.NETを使用してみましたが、子オブジェクト自体が JObject でIDictionary<string, JToken>あるため、階層全体を反復処理して再度変換する必要があります。

既存のシリアライザーを使用してこの問題を解決する方法を誰かが知っていますか?

編集

Dictionary<string, object>オブジェクトがサーバー呼び出しごとに異なるため (たとえば、"Id"プロパティは、要求に応じて"id"、 *"cust_id"* または"customerId"になる可能性があります)、および私のアプリだけではないため、使用しています。これらのサービスを使用しているアプリを変更することはできません。少なくとも今のところは変更できません。

したがって、この状況でDataContractAttributeDataMemberAttributeを使用するのは不便であることがわかりました。代わりに、すべてを一般的なディクショナリに格納し、ディクショナリで「id」、「cust_id」、または「customerId」を検索して UI に対して透過的にする単一の厳密に型指定されたプロパティ「Id」を持ちたいと考えています。

このシステムは JSON.NET でうまく機能しますが、サーバーがオブジェクト階層を返す場合、サブオブジェクトは別の辞書ではなく私の辞書に JObject として格納されます。

Dictionary<string, object>要約すると、WinRT で利用可能な JSON シリアライザーを使用して、オブジェクト階層を階層に変換する効率的なシステムを探しています。

4

2 に答える 2

4

JSON.NET ライブラリと ExpandoObject クラスの組み合わせを使用して、WinRT アプリでこの同じ問題に対処しています。このライブラリは、JSON データを IDictionary を実装する ExpandoObjects に非常にうまく逆シリアル化できます。ExpandoObject のキーと値のペアの値は、別の ExpandoObject として簡単に扱うことができます。

あなたのサンプルに適応した、私が使用したアプローチは次のとおりです。

void LoadJSONData()
{
    string testData = "{ \"Name\":\"John Smith\", \"Age\":42, \"Parent\": { \"Name\":\"Brian Smith\", \"Age\":65, \"Parent\": { \"Name\":\"James Smith\", \"Age\":87, } } }";

    ExpandoObject dataObj = JsonConvert.DeserializeObject<ExpandoObject>(testData, new ExpandoObjectConverter());

    // Grab the parent object directly (if it exists) and treat as ExpandoObject
    var parentElement = dataObj.Where(el => el.Key == "Parent").FirstOrDefault();
    if (parentElement.Value != null && parentElement.Value is ExpandoObject)
    {
        ExpandoObject parentObj = (ExpandoObject)parentElement.Value;
        // do something with the parent object...
    }

    // Alternately, iterate through the properties of the expando
    foreach (var property in (IDictionary<String, Object>)dataObj)
    {
        if (property.Key == "Parent" && property.Value != null && property.Value is ExpandoObject)
        {
            foreach (var parentProp in (ExpandoObject)property.Value)
            {
                // do something with the properties in the parent expando
            }
        }
    }
}
于 2012-11-30T17:12:25.630 に答える
3

次のコード スニペットを試してください。

var d = new System.Web.Script.Serialization.JavaScriptSerializer();
var results = d.Deserialize<Dictionary<string, object>>(jsonString);
var parent = (Dictionary<string, object>)results["Parent"];

リファレンスによると、JavaScriptSerializer クラスはWindows 8をサポートしています。

デシリアライゼーションについては、Json.NETWindows 8のサポートを検討するオプションです。

追加、 の場合WinRT:

  1. DataContractJSON に従って を定義します。

    [DataContract]
    public class CustomObject
    {
        [DataMember(Name = "Name")]
        public string Name { get; set; }
    
        [DataMember(Name = "Age")]
        public string Age { get; set; }
    
        [DataMember(Name = "Parent")]
        public Dictionary<string, object> Parent { get; set; }
    }
    
  2. DataContract逆シリアル化中にクラスを使用します。

    using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
    {
        DataContractJsonSerializerSettings settings = 
                new DataContractJsonSerializerSettings();
        settings.UseSimpleDictionaryFormat = true;
    
        DataContractJsonSerializer serializer = 
                new DataContractJsonSerializer(typeof(CustomObject), settings);
    
        CustomObject results = (CustomObject)serializer.ReadObject(ms);
        Dictionary<string, object> parent = results.Parent;
    }
    

参照: DataContractJsonSerializer を使用して JSON から .NET オブジェクトを作成する

于 2012-11-29T17:26:10.827 に答える