用JsonIgnoreAttribute标记私有设置

本文关键字:设置 JsonIgnoreAttribute | 更新日期: 2023-09-27 17:50:47

我注意到,默认情况下,JSON。. NET将只(反)序列化对象的公共属性。这很好。然而,当一个属性被标记为[JsonPropertyAttribute]时,JSON。NET还将访问私有 getter和setter。

我想做的是解决这个问题是标记私有getter/setter与[JsonIgnoreAttribute]

例如:

public class JsonObject
{
    [JsonProperty(PropertyName = "read_write_property")]
    public object ReadOnlyProperty
    {
        get;
        [JsonIgnore] private set;
    }
}
不幸的是,这不是有效的c#代码。那么什么代码可以达到相同的结果呢?

我知道的一些可行的方法:

  1. 删除[JsonPropertyAttribute]
  2. 完全删除setter并引入一个后备字段

只有这两个选项吗?

编辑

我为我的只读属性添加了后备字段。不确定,但我想我在Json.Net中发现了一个bug。当只有getter存在时,序列化器将把该属性视为不存在,即使指定的name属性与JSON字符串匹配。这是特别恼人的,因为我也使用[JsonExtensionData]机制。反序列化的值最终会进入扩展数据字典。下面是演示这个问题的代码:

<<p> 冒犯类/strong>
using System.ComponentModel;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public class JsonObject
{
    private readonly BindingDirection bindingDirection;
    public JsonObject()
    {
        this.bindingDirection = BindingDirection.OneWay;
    }
    [JsonProperty(PropertyName = "binding_type"), JsonConverter(typeof(StringEnumConverter))]
    public BindingDirection BindingDirection
    {
        get
        {
            return this.bindingDirection;
        }
    }
    [JsonExtensionData]
    public IDictionary<string, object> ExtensionData { get; set; }
}

using Newtonsoft.Json;
class Program
{
    static void Main(string[] args)
    {
        var obj = new JsonObject();
        var serialized = JsonConvert.SerializeObject(obj);
        var deserialized = JsonConvert.DeserializeObject<JsonObject>(serialized);
        Console.WriteLine("*** Extension data ***'n");
        foreach (var kvp in deserialized.ExtensionData)
        {
            Console.WriteLine("{0} == {1}", kvp.Key, kvp.Value);
        }
        Console.ReadLine();
    }
}

***扩展数据

binding_type == OneWay

用JsonIgnoreAttribute标记私有设置

Json。当使用[JsonProperty]属性标记时,Net访问私有成员实际上是通过设计的。这个特性的存在是为了启用Json。Net用于序列化/反序列化对象的内部状态(例如持久化它),而不需要为该状态公开公共接口。
来自文档:

JsonPropertyAttribute

JsonPropertyAttribute有很多用途:

  • 默认情况下,JSON属性将与。net属性具有相同的名称。此属性允许自定义名称。

  • 表示当成员序列化设置为opt-in时,应该序列化某个属性。

  • 包含序列化和反序列化中的非公共属性。

  • 自定义属性值的类型名称、引用、null和默认值处理。

  • 自定义属性的集合项JsonConverter,类型名称处理和引用处理

不幸的是,[JsonProperty]属性的参数显然没有提供一种方法来选择不包含非公共成员,同时仍然允许您使用其他功能,例如更改属性名称。因此,在这种情况下,您将不得不使用变通方法。

你已经提到了几种可能性,我再加上第三种:

  1. 删除[JsonPropertyAttribute]
  2. 完全删除setter并引入一个后备字段
  3. 为您的类实现自定义JsonConverter

其中,第二个是最干净和最容易实现的,同时仍然达到您正在寻找的结果:公共属性将使用自定义属性名称序列化,而私有支持字段在反序列化期间不会受到影响。

第一个选项,删除属性,不会得到你想要的。虽然它将防止字段被反序列化为,但您将不得不在序列化期间将原始属性名称写入JSON。

第三种选择,编写转换器,使您可以完全控制类的序列化和反序列化方式。你可以改变属性名,省略属性,包括类中没有的附加信息,等等。它们并不难写;但是,如果您真正需要的只是一个简单的后备字段来解决问题,那么转换器在这里可能是多余的。也就是说,如果您真的对这个选项感兴趣,我很乐意提供一个简单的示例。让我知道。

编辑

关于你的扩展数据问题——你是对的,这看起来确实像个bug。当我最初试图重现这个问题时,我不能,因为我的JsonObject版本不包含默认构造函数。我假设您的构造函数有一个参数来接受只读属性的初始值。一旦我删除了参数,它就开始不正常了。我不确定为什么构造函数会对JsonExtensionData的解释产生影响。然而,这确实建议了一个奇怪的解决方法:尝试将以下代码添加到您的类中,看看是否可以解决问题。

    [JsonConstructor]
    private JsonObject(string dummy) : this()
    {
    }