Как десериализовать дочерний объект с динамическими (числовыми) именами клавиш?

как я могу десериализовать ниже json-структуру, используя newtonsoft json.net в .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 ». Path ‘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(json); } } class RootObject { public string ParentName { get; set; } public Dictionary 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 есть дополнительный уровень вложенности, причем корневой объект содержит одно свойство "users" :

     { "users" : { ... } } 

    Ваша модель данных должна отражать это.

  • Ваш объект "users" имеет смесь известных и неизвестных имен свойств. Вопрос Deserialize json с известными и неизвестными полями обращается к аналогичной ситуации, однако в вашем случае ваши неизвестные свойства всегда имеют фиксированную схему, а их значения должны быть десериализованы в словарь POCOs – в частности, classа User . Поэтому ответы там не вполне отвечают вашим потребностям, а также встроенные функции [JsonExtensionData] .

Следующий преобразователь позволяет десериализовать неизвестные свойства в типизированный контейнер, а не в словарь произвольных типов:

 [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] public class JsonTypedExtensionDataAttribute : Attribute { } public class TypedExtensionDataConverter : 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(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 : IDisposable { Action setValue; T oldValue; public PushValue(T value, Func getValue, Action 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(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 AsList(this IList container) { return container; } } 

Затем используйте его в своих classах следующим образом:

 class RootObject { [JsonProperty("users")] public Users Users { get; set; } } [JsonConverter(typeof(TypedExtensionDataConverter))] class Users { public Users() { this.UserTable = new Dictionary(); } [JsonProperty("parentname")] public string ParentName { get; set; } [JsonTypedExtensionData] public Dictionary UserTable { get; set; } } class User { public string name { get; set; } public string state { get; set; } public string id { get; set; } } 

Я написал конвертер довольно обычным способом, чтобы его можно было повторно использовать. Преобразователь, жестко запрограммированный для типа « Users », требует меньше кода.

Ваш Json должен выглядеть так:

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

Чтобы десериализировать его с помощью вашей classовой структуры:

 class RootObject { public string ParentName { get; set; } public Dictionary 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:

 var root = JsonConvert.DeserializeObject(json); 
  • Событие KeyTime delete (backspace)
  • Карта Google подписала ошибки api в Android
  • Ограничение таблицы SQLite - уникальное по нескольким столбцам
  • Как удалить дубликаты на основе ключа в Mongodb?
  • Как создать уникальный открытый и закрытый ключ через RSA
  • Interesting Posts
    Давайте будем гением компьютера.