C# 如何使用动态(数字)键名反序列化子对象?
如何在.net中使用newtonsoft json.net反序列化json结构下面的内容C# 如何使用动态(数字)键名反序列化子对象?,c#,dynamic,json.net,key,C#,Dynamic,Json.net,Key,如何在.net中使用newtonsoft json.net反序列化json结构下面的内容 { "users" : { "parentname":"test", "100034" : { "name" : "tom", "state" : "WA", "id" : "cedf-c56f-18a4-4b1" }, "10045" : {
{
"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; }
}
类程序
{
静态void Main(字符串[]参数)
{
字符串json=@”
{
“用户”:{
“父项名称”:“测试”,
""10045"": {
“姓名”:“史蒂夫”,
“州”:“纽约”,
“id”:“ebb2-92bf-3062-7774”
}
}
}";
RootObject root=JsonConvert.DeserializeObject(json);
}
}
类根对象
{
公共字符串ParentName{get;set;}
公共字典用户{get;set;}
}
类用户
{
公共字符串名称{get;set;}
公共字符串状态{get;set;}
公共字符串id{get;set;}
公共字符串ParentName{get;set;}
}
请建议。您的Json必须如下所示:
{
"ParentName":"test",
"users":{
"10045":{
"name":"steve",
"state":"NY",
"id":"ebb2-92bf-3062-7774",
"ParentName":"someOtherName"
}
}
}
要使用给定的类结构对其进行反序列化:
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; }
}
类根对象
{
公共字符串ParentName{get;set;}
公共字典用户{get;set;}
}
类用户
{
公共字符串名称{get;set;}
公共字符串状态{get;set;}
公共字符串id{get;set;}
公共字符串ParentName{get;set;}
}
现在,您可以使用以下命令反序列化Json字符串:
var root = JsonConvert.DeserializeObject<RootObject>(json);
var root=JsonConvert.DeserializeObject(json);
您的Json必须如下所示:
{
"ParentName":"test",
"users":{
"10045":{
"name":"steve",
"state":"NY",
"id":"ebb2-92bf-3062-7774",
"ParentName":"someOtherName"
}
}
}
要使用给定的类结构对其进行反序列化:
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; }
}
类根对象
{
公共字符串ParentName{get;set;}
公共字典用户{get;set;}
}
类用户
{
公共字符串名称{get;set;}
公共字符串状态{get;set;}
公共字符串id{get;set;}
公共字符串ParentName{get;set;}
}
现在,您可以使用以下命令反序列化Json字符串:
var root = JsonConvert.DeserializeObject<RootObject>(json);
var root=JsonConvert.DeserializeObject(json);
您有几个问题:
- JSON具有额外的嵌套级别,根对象包含单个属性
: 您的数据模型需要反映这一点“users”
- 您的
对象混合了已知和未知的属性名。这个问题解决了一个类似的情况,但是在您的情况下,您的未知属性总是有一个固定的模式,它们的值应该反序列化到POCO字典中——特别是“用户”
类。因此,那里的答案不能完全满足您的需求,内置功能也不能User
[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; }
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property,AllowMultiple=false)]
公共类JsonTypedExtensionDataAttribute:属性
{
}
公共类TypedExtensionDataConverter:JsonConverter
{
公共覆盖布尔CanConvert(类型objectType)
{
返回typeof(TObject).IsAssignableFrom(objectType);
}
JsonProperty GetExtensionJsonProperty(JSONObject合同)
{
尝试
{
返回contract.Properties.Where(p=>p.AttributeProvider.GetAttributes(typeof(JsonTypedExtensionDataAttribute),false).Any()).Single();
}
捕获(无效操作异常ex)
{
抛出新的JsonSerializationException(string.Format(“对于类型{0}”、contract.underyingType,需要一个具有JsonTypedExtensionDataAttribute的属性),例如);
}
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
if(reader.TokenType==JsonToken.Null)
返回null;
var jObj=JObject.Load(读卡器);
var contract=(JsonObjectContract)序列化程序.ContractResolver.ResolveContract(objectType);
var extensionJsonProperty=GetExtensionJsonProperty(合同);
var extensionJProperty=(JProperty)null;
对于(int i=jObj.Count-1;i>=0;i--)
{
var属性=(JProperty)jObj.AsList()[i];
if(contract.Properties.GetClosestMatchProperty(property.Name)==null)
{
if(extensionJProperty==null)
{
extensionJProperty=newjproperty(extensionJsonProperty.PropertyName,new JObject());
jObj.Add(extensionJProperty);
}
((JObject)extensionJProperty.Value).Add(property.RemoveFromLowestPossibleParent());
}
}
var value=existingValue??contract.DefaultCreator();
使用(var subReader=jObj.CreateReader())
序列化程序。填充(子读取器,值);
返回值;
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
var contract=(JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType());
var extensionJsonProperty=GetExtensionJsonProperty(合同);
JObject jObj;
使用(新的PushValue(true,()=>禁用,(canWrite)=>禁用=canWrite))
{
jObj=JObject.FromObject(值,序列化程序);
}
var extensionValue=(作为JObject的jObj[extensionJsonProperty.PropertyName]);
if(extensionValue!=null)
{
对于(int i=extensionValue.Count-1;i>=0;i--)
{
var属性=(JProperty)extensionValue.AsList()[i];
Add(property.RemoveFromLowestPossibleParent());
}
}
jObj.WriteTo(作家);
}
[线程静态]
静态布尔禁用;