【问题标题】:Assign the same JsonProperty to two properties on class将相同的 JsonProperty 分配给类上的两个属性
【发布时间】:2022-03-15 04:04:31
【问题描述】:

从请求中反序列化 JSON 属性时,我想将它用于对象上的两个不同属性。例如;

public class Example
{
    [JsonProperty(PropertyName = "favoriteColor")]
    public string favoriteColor { get; set; }

    [JsonProperty(PropertyName = "favoriteColor")]
    public string oldFavoriteColor { get; set; }
}

但是这会导致错误:

“Example”中已存在名为“favoriteColor”的成员。使用 JsonPropertyAttribute 指定另一个名称。

如果这正是我想要的,我该怎么做?

【问题讨论】:

    标签: c# json json.net


    【解决方案1】:

    我认为您可以修改其中一个属性的 set 方法,以便无论何时设置它,它也会设置另一个属性

    例如

    public class Example
    {
        [JsonProperty(PropertyName = "favoriteColor")]
        public string favoriteColor { 
          get { return favoriteColor; }
          set
          {
            favoriteColor = value;
            if (oldFavoriteColor == null) {
              oldFavoriteColor = value;
            }
          }
        }
    
        public string? oldFavoriteColor { get; set; }
    }
    

    【讨论】:

    • 套装的修改可能会过火。它可能会产生不必要的副作用。 JSON 是一种用于序列化的方法。所以在这里提供一个自定义的序列化/反序列化函数可能会更好。这完全超出了自动装置可以为您做的事情。在这种特定情况下(颜色和旧颜色)它可能会起作用。但我更愿意将其设置为无/其他特定值,表示尚未设置它。
    • 出于好奇,我尝试了另一种方法,即自定义序列化程序。这个解决方案(修改Set)a)使用更少的代码行,并且b)确保属性实际上保持同步。对我来说,潜在的问题是有两个具有相同值的属性。如果未来的开发人员看到两个几乎相同的属性并且他们浪费时间猜测要使用哪一个或挖掘代码试图弄清楚它们是如何填充的,那么他们肯定会感到困惑。
    【解决方案2】:

    可能有更好的答案,即从问题中退后一步,看看是否有完全不同的方法。特别是,为什么需要一个具有两个具有相同值的属性的类? 除了从 JSON 反序列化之外,该类的每个其他使用者都知道这两个属性需要保持同步吗?为什么?

    但这回答了直接的问题。

    [JsonProperty] 属性用于序列化和反序列化。如果您有两个具有相同 [JsonProperty] 属性的属性,那么当您将对象序列化为 JSON 时,您将拥有两个具有相同名称的属性。

    您可以像这样创建自定义 JSON 序列化程序。如您所见,在反序列化 Example 后,它将使用 oldFavoriteColor 属性的值填充 favoriteColor 属性。

    public class ExampleConverter : CustomCreationConverter<Example>
    {
        public override Example Create(Type objectType)
        {
            return new Example();
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, 
            object existingValue, JsonSerializer serializer)
        {
            var result = (Example)base.ReadJson(reader, objectType, existingValue, 
                serializer);
            result.favoriteColor = result.oldFavoriteColor;
            return result;
        }
    }
    

    为了使其工作,您还必须告诉序列化程序不要尝试反序列化 favoriteColor 属性。即使没有[JsonProperty] 属性,[JsonProperty(PropertyName = "favoriteColor")] 和另一个实际名为“favoriteColor”的属性之间仍然存在冲突。

    public class Example
    {
        [JsonIgnore]
        public string favoriteColor { get; set; }
    
        [JsonProperty(PropertyName = "favoriteColor")]
        public string oldFavoriteColor { get; set; }
    }
    

    要确认的单元测试:

    public void DeserializerPopulatesFavoriteColorFromOldFavoriteColor()
    {
        var json = @"{ favoriteColor: ""Green""}";
        var deserialized = JsonConvert.DeserializeObject<Example>(json, new ExampleConverter());
        Assert.AreEqual("Green", deserialized.oldFavoriteColor);
        Assert.AreEqual(deserialized.oldFavoriteColor, deserialized.favoriteColor);
    }
    

    【讨论】:

    • 因此,关于“您还必须告诉序列化程序不要尝试反序列化”,如果传入属性是 color 而不是目标对象上存在的属性,则您的说法;那么favoriteColoroldFavoriteColor 可以有自己的CustomCreationConverters,它应该可以工作吗?
    • 如果您有一个名为“favoriteColor”的属性,然后是一个名称不同但属性为[JsonProperty(PropertyName = "favoriteColor")] 的属性,您将收到与您的问题相同的错误。为了使用自定义转换器,您首先必须清除这些问题。您不能有竞争/冲突的属性名称和属性。一旦你把那部分整理好,你就可以在自定义转换器中做任何你想做的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-01
    • 2020-06-24
    • 2021-08-06
    • 2021-06-22
    • 1970-01-01
    相关资源
    最近更新 更多