用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#代码。那么什么代码可以达到相同的结果呢?我知道的一些可行的方法:
- 删除[JsonPropertyAttribute]
- 完全删除setter并引入一个后备字段
只有这两个选项吗?
编辑
我为我的只读属性添加了后备字段。不确定,但我想我在Json.Net中发现了一个bug。当只有getter存在时,序列化器将把该属性视为不存在,即使指定的name属性与JSON字符串匹配。这是特别恼人的,因为我也使用[JsonExtensionData]
机制。反序列化的值最终会进入扩展数据字典。下面是演示这个问题的代码:
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
Json。当使用[JsonProperty]
属性标记时,Net访问私有成员实际上是通过设计的。这个特性的存在是为了启用Json。Net用于序列化/反序列化对象的内部状态(例如持久化它),而不需要为该状态公开公共接口。
来自文档:
JsonPropertyAttribute
JsonPropertyAttribute有很多用途:
默认情况下,JSON属性将与。net属性具有相同的名称。此属性允许自定义名称。
表示当成员序列化设置为opt-in时,应该序列化某个属性。
包含序列化和反序列化中的非公共属性。
自定义属性值的类型名称、引用、null和默认值处理。
自定义属性的集合项JsonConverter,类型名称处理和引用处理
不幸的是,[JsonProperty]
属性的参数显然没有提供一种方法来选择不包含非公共成员,同时仍然允许您使用其他功能,例如更改属性名称。因此,在这种情况下,您将不得不使用变通方法。
你已经提到了几种可能性,我再加上第三种:
- 删除
[JsonPropertyAttribute]
- 完全删除setter并引入一个后备字段
- 为您的类实现自定义
JsonConverter
其中,第二个是最干净和最容易实现的,同时仍然达到您正在寻找的结果:公共属性将使用自定义属性名称序列化,而私有支持字段在反序列化期间不会受到影响。
第一个选项,删除属性,不会得到你想要的。虽然它将防止字段被反序列化为,但您将不得不在序列化期间将原始属性名称写入JSON。
第三种选择,编写转换器,使您可以完全控制类的序列化和反序列化方式。你可以改变属性名,省略属性,包括类中没有的附加信息,等等。它们并不难写;但是,如果您真正需要的只是一个简单的后备字段来解决问题,那么转换器在这里可能是多余的。也就是说,如果您真的对这个选项感兴趣,我很乐意提供一个简单的示例。让我知道。
编辑
关于你的扩展数据问题——你是对的,这看起来确实像个bug。当我最初试图重现这个问题时,我不能,因为我的JsonObject
版本不包含默认构造函数。我假设您的构造函数有一个参数来接受只读属性的初始值。一旦我删除了参数,它就开始不正常了。我不确定为什么构造函数会对JsonExtensionData的解释产生影响。然而,这确实建议了一个奇怪的解决方法:尝试将以下代码添加到您的类中,看看是否可以解决问题。
[JsonConstructor]
private JsonObject(string dummy) : this()
{
}