我如何在.net中使用newtonsoft json.net在json结构下反序列化。
{ "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" } } }
我尝试了下面的代码,但无法正常工作。我收到错误“将值“ test”转换为类型“ 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; } }
请提出建议。
您有几个问题:
"users"
{ "users" : { ... }
}
您的数据模型需要反映这一点。
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类型的转换器将需要较少的代码。
Users