【问题标题】:json.net object with two nullable properties serialize to single property具有两个可为空属性的 json.net 对象序列化为单个属性
【发布时间】:2012-10-19 23:15:12
【问题描述】:

我想使用 json.net 来序列化 jquery ui 小部件的选项,例如jquery 手风琴。

但是手风琴有一个属性 active 可以是以下之一:

一个基于 0 的整数,用于定义活动选项卡,

一个布尔值,当设置为 false 时,将折叠所有手风琴。

我正在考虑创建 2 个可为空的 .NET 属性:

int? Active

bool? IsActive

如果 Active 不为 null,则应将其序列化为具有属性名称 active 的整数, 如果 IsActive 不为 null,则应将其序列化为具有相同名称 active 的布尔值。 .Net 代码将确保其中只有一个不能为空。

但是当我将 [JsonProperty("active")] 放在两个属性上时,它不起作用......还有其他选择吗?

【问题讨论】:

    标签: json.net


    【解决方案1】:

    您当前方法的困难在于,拥有这两个字段将不起作用,因为您无法同时标记它们[JsonProperty("active")]。我的第一次尝试是将类定义如下:

    class Accordion
    {
        [JsonProperty("active")]
        [JsonConverter(typeof(ActiveTabConverter))]
        public int Active { get; set; }
    
        [JsonProperty("active")]
        [JsonConverter(typeof(ActiveTabConverter))]
        public bool IsActive { get; set; }
    }
    

    这会导致异常(我想你也有这个),因为我在两个属性上使用了 [JsonProperty("active")]。删除其中一个属性也不起作用:没有例外,但是从其中删除属性的字段从未反序列化。

    以下是起作用的:

    class Accordion
    {
        [JsonProperty("active")]
        [JsonConverter(typeof(ActiveTabConverter))]
        public int Active { get; set; }
    
        [JsonIgnore]
        public bool IsActive
        {
            get
            {
                return this.Active > -1;
            }
        }
    
        public Accordion()
        {
            this.Active = -1;
        }
    }
    

    请注意,仍然有两个字段,但只有其中一个会被反序列化。 IsActive 是一个辅助属性。我在这里遵循的约定是Active 值大于 0 表示打开手风琴选项卡,而 -1 相当于从 JSON 接收false

    class ActiveTabConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(int) || objectType == typeof(bool);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType,
            JsonSerializer serializer)
        {
            var value = JValue.ReadFrom(reader);
    
            if (value.Type == JTokenType.Integer)
            {
                return serializer.Deserialize<int>(reader);
            }
    
            return -1;
        }
    
        public override void WriteJson(JsonWriter writer, object value,
            JsonSerializer serializer)
        {
            int item = (int)value;
    
            if (item == -1)
            {
                writer.WriteValue(false);
            }
            else
            {
                writer.WriteValue(item);
            }
    
            writer.Flush();
        }
    }
    

    这个类负责反序列化和序列化Active值。

    我使用以下代码进行序列化/反序列化。请注意,JSON 实际上来自 jQuery 手风琴。对于有问题的一个属性来说,这太过分了,但我认为最好使用真实数据。

    string json1 = "{\"disabled\":false,\"create\":null,\"active\":2,\"animate\":300,\"collapsible\":false,\"event\":\"click\",\"header\":\"> li > :first-child,> :not(li):even\",\"heightStyle\":\"auto\",\"icons\":{\"activeHeader\":\"ui-icon-triangle-1-s\",\"header\":\"ui-icon-triangle-1-e\",\"headerSelected\":\"ui-icon-triangle-1-s\"},\"activate\":null,\"beforeActivate\":null,\"navigation\":false,\"autoHeight\":true,\"clearStyle\":false,\"fillSpace\":false,\"change\":null,\"changestart\":null,\"animated\":\"slide\"}";
    string json2 = "{\"disabled\":false,\"create\":null,\"active\":false,\"animate\":300,\"collapsible\":true,\"event\":\"click\",\"header\":\"> li > :first-child,> :not(li):even\",\"heightStyle\":\"auto\",\"icons\":{\"activeHeader\":\"ui-icon-triangle-1-s\",\"header\":\"ui-icon-triangle-1-e\",\"headerSelected\":\"ui-icon-triangle-1-s\"},\"activate\":null,\"beforeActivate\":null,\"navigation\":false,\"autoHeight\":true,\"clearStyle\":false,\"fillSpace\":false,\"change\":null,\"changestart\":null,\"animated\":\"slide\"}";
    
    Accordion accordion = JsonConvert.DeserializeObject<Accordion>(json1);
    string serializedJson = JsonConvert.SerializeObject(accordion);
    
    accordion = JsonConvert.DeserializeObject<Accordion>(json2);
    serializedJson = JsonConvert.SerializeObject(accordion);
    

    【讨论】:

    • 你的解决方案没问题,但我正在寻找(当然如果可能的话)更通用的方法,因为我也希望序列化其他 jquery ui 小部件的选项。我有点担心我必须为所有不同的情况添加大量转换器。
    • 转换器的数量取决于您想要序列化的其他小部件 - 这种方法的唯一原因是 active 属性既是布尔值又是整数:您可能不一定会遇到其他问题小部件。此外,您可以很高兴地在其他布尔/整数场景中重用ActiveTabConverter;它不是特定于 Active 属性的。
    • 不幸的是,jquery 小部件中有几个属性可以接受多种数据类型,而不仅仅是整数/布尔值
    猜你喜欢
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 2014-02-27
    • 1970-01-01
    • 2017-03-21
    • 2013-07-09
    • 1970-01-01
    相关资源
    最近更新 更多