栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

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

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

您有几个问题:

  • 您的JSON具有更高级别的嵌套,其根对象包含单个属性
    "users"
    {"users" : { ... }

    }

您的数据模型需要反映这一点。

  • 您的
    "users"
    对象混合了已知和未知的属性名称。具有已知字段和未知字段的反序列化JSON问题解决了类似的情况,但是在您的情况下,您的未知属性始终具有固定的架构,应将其值反序列化为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
类型的转换器将需要较少的代码。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/432964.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号