2016-10-17 14 views
1

どのようにすることができますjson構造の下で逆変換することができます.netでnewtonsoft json.netを使用します。動的(数値)キー名を使用して子オブジェクトを逆シリアル化する方法はありますか?

{ 
    "users" : { 
     "parentname":"test", 
     "100034" : { 
      "name" : "tom", 
      "state" : "WA", 
      "id" : "cedf-c56f-18a4-4b1" 
     }, 
     "10045" : { 
      "name" : "steve", 
      "state" : "NY", 
      "id" : "ebb2-92bf-3062-7774" 
     }, 
     "12345" : { 
      "name" : "mike", 
      "state" : "MA", 
      "id" : "fb60-b34f-6dc8-aaf7" 
     } 
    } 
} 

私は以下のコードを試しましたが、動作しません。私はエラー '値を変換するエラー "テスト"を入力する' ConsoleApplication2.User '。パス 'users.parentname'、5行目、35桁目。 '

class Program 
    { 
     static void Main(string[] args) 
     { 
      string json = @" 
     { 

      ""users"": { 
       ""parentname"":""test"", 
       ""10045"": { 
        ""name"": ""steve"", 
        ""state"": ""NY"", 
        ""id"": ""ebb2-92bf-3062-7774"" 
       } 
      } 
     }"; 

      RootObject root = JsonConvert.DeserializeObject<RootObject>(json); 
     } 
    } 

    class RootObject 
    { 
     public string ParentName { get; set; } 
     public Dictionary<string, User> users { get; set; } 
    } 
    class User 
    { 
     public string name { get; set; } 
     public string state { get; set; } 
     public string id { get; set; } 
     public string ParentName { get; set; } 
    } 

お勧めします。

+2

本当にあなたのユーザーオブジェクト内にparentnameを持っていますか?ルートレベルに置くとコードが動作します( 'ParentName'プロパティを' parentname'に変更してJSONにマッチさせる必要があります)。 – bib1257

+0

'RootObject'と' User'オブジェクトに 'ParentName'プロパティがあるのはなぜですか?それの後ろに深い意味がありますか? – croxy

+0

このjsonはクライアントによって与えられます..変更できません:( – amit

答えて

3

あなたはいくつかの問題があります:

  • あなたのJSONは、単一のプロパティ"users"を含むルートオブジェクトと、ネストの余分なレベルを持っています

    { 
        "users" : { ... } 
    } 
    

    あなたのデータモデルはこれを反映する必要があります。

  • "users"オブジェクトには、既知のプロパティ名と未知のプロパティ名が混在しています。質問Deserialize json with known and unknown fieldsは同様の状況に対処しますが、未知のプロパティは常に固定スキーマを持ち、その値はPOCOの辞書(具体的にはUserクラス)に逆シリアル化する必要があります。したがって、そこの回答はあなたのニーズを十分に満たしておらず、組み込み機能[JsonExtensionData]もありません。その後

    [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] 
    public class JsonTypedExtensionDataAttribute : Attribute 
    { 
    } 
    
    public class TypedExtensionDataConverter<TObject> : JsonConverter 
    { 
        public override bool CanConvert(Type objectType) 
        { 
         return typeof(TObject).IsAssignableFrom(objectType); 
        } 
    
        JsonProperty GetExtensionJsonProperty(JsonObjectContract contract) 
        { 
         try 
         { 
          return contract.Properties.Where(p => p.AttributeProvider.GetAttributes(typeof(JsonTypedExtensionDataAttribute), false).Any()).Single(); 
         } 
         catch (InvalidOperationException ex) 
         { 
          throw new JsonSerializationException(string.Format("Exactly one property with JsonTypedExtensionDataAttribute is required for type {0}", contract.UnderlyingType), ex); 
         } 
        } 
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
        { 
         if (reader.TokenType == JsonToken.Null) 
          return null; 
         var jObj = JObject.Load(reader); 
         var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType); 
         var extensionJsonProperty = GetExtensionJsonProperty(contract); 
    
         var extensionJProperty = (JProperty)null; 
         for (int i = jObj.Count - 1; i >= 0; i--) 
         { 
          var property = (JProperty)jObj.AsList()[i]; 
          if (contract.Properties.GetClosestMatchProperty(property.Name) == null) 
          { 
           if (extensionJProperty == null) 
           { 
            extensionJProperty = new JProperty(extensionJsonProperty.PropertyName, new JObject()); 
            jObj.Add(extensionJProperty); 
           } 
           ((JObject)extensionJProperty.Value).Add(property.RemoveFromLowestPossibleParent()); 
          } 
         } 
    
         var value = existingValue ?? contract.DefaultCreator(); 
         using (var subReader = jObj.CreateReader()) 
          serializer.Populate(subReader, value); 
         return value; 
        } 
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
        { 
         var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType()); 
         var extensionJsonProperty = GetExtensionJsonProperty(contract); 
    
         JObject jObj; 
         using (new PushValue<bool>(true,() => Disabled, (canWrite) => Disabled = canWrite)) 
         { 
          jObj = JObject.FromObject(value, serializer); 
         } 
    
         var extensionValue = (jObj[extensionJsonProperty.PropertyName] as JObject).RemoveFromLowestPossibleParent(); 
         if (extensionValue != null) 
         { 
          for (int i = extensionValue.Count - 1; i >= 0; i--) 
          { 
           var property = (JProperty)extensionValue.AsList()[i]; 
           jObj.Add(property.RemoveFromLowestPossibleParent()); 
          } 
         } 
    
         jObj.WriteTo(writer); 
        } 
    
        [ThreadStatic] 
        static bool disabled; 
    
        // Disables the converter in a thread-safe manner. 
        bool Disabled { get { return disabled; } set { disabled = value; } } 
    
        public override bool CanWrite { get { return !Disabled; } } 
    
        public override bool CanRead { get { return !Disabled; } } 
    } 
    
    public struct PushValue<T> : IDisposable 
    { 
        Action<T> setValue; 
        T oldValue; 
    
        public PushValue(T value, Func<T> getValue, Action<T> setValue) 
        { 
         if (getValue == null || setValue == null) 
          throw new ArgumentNullException(); 
         this.setValue = setValue; 
         this.oldValue = getValue(); 
         setValue(value); 
        } 
    
        #region IDisposable Members 
    
        // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class. 
        public void Dispose() 
        { 
         if (setValue != null) 
          setValue(oldValue); 
        } 
    
        #endregion 
    } 
    
    public static class JsonExtensions 
    { 
        public static TJToken RemoveFromLowestPossibleParent<TJToken>(this TJToken node) where TJToken : JToken 
        { 
         if (node == null) 
          return null; 
         var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault(); 
         if (contained != null) 
          contained.Remove(); 
         // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should 
         if (node.Parent is JProperty) 
          ((JProperty)node.Parent).Value = null; 
         return node; 
        } 
    
        public static IList<JToken> AsList(this IList<JToken> container) { return container; } 
    } 
    

    次のように自分のクラスでそれを使用する:

次コンバータではなく、任意の種類の辞書に比べ型付けコンテナ、にデシリアライズする未知の特性をすることができます

class RootObject 
{ 
    [JsonProperty("users")] 
    public Users Users { get; set; } 
} 

[JsonConverter(typeof(TypedExtensionDataConverter<Users>))] 
class Users 
{ 
    public Users() 
    { 
     this.UserTable = new Dictionary<string, User>(); 
    } 

    [JsonProperty("parentname")] 
    public string ParentName { get; set; } 

    [JsonTypedExtensionData] 
    public Dictionary<string, User> UserTable { get; set; } 
} 

class User 
{ 
    public string name { get; set; } 
    public string state { get; set; } 
    public string id { get; set; } 
} 

私はかなり一般的な方法でコンバータを書きましたので、再利用することができます。 Usersタイプのハードコーディングされたコンバータは、コードが少なくて済みます。

0

あなたのJSONはこのように見ています

{ 
    "ParentName":"test", 
    "users":{ 
     "10045":{ 
     "name":"steve", 
     "state":"NY", 
     "id":"ebb2-92bf-3062-7774", 
     "ParentName":"someOtherName" 
     } 
    } 
} 

自分の与えられたクラス構造と、それをデシリアライズするために:

var root = JsonConvert.DeserializeObject<RootObject>(json); 

class RootObject 
{ 
    public string ParentName { get; set; } 
    public Dictionary<string, User> users { get; set; } 
} 

class User 
{ 
    public string name { get; set; } 
    public string state { get; set; } 
    public string id { get; set; } 
    public string ParentName { get; set; } 
} 

今、あなたがJSON文字列をデシリアライズすることができます

関連する問題