C# 如何使用动态(数字)键名反序列化子对象?

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" : {

如何在.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; }
    }
类程序
{
静态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(作家);
}
[线程静态]
静态布尔禁用;