gpt4 book ai didi

c# - 使用 JsonIgnoreAttribute 标记私有(private) setter

转载 作者:行者123 更新时间:2023-11-30 20:50:31 25 4
gpt4 key购买 nike

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

要解决此问题,我想做的是用 [JsonIgnoreAttribute] 标记私有(private) getter/setter。

例如:

public class JsonObject
{
[JsonProperty(PropertyName = "read_write_property")]
public object ReadOnlyProperty
{
get;
[JsonIgnore] private set;
}
}

不幸的是,这不是有效的 C# 代码。那么什么样的代码会达到相同的结果呢?

我知道一些可行的想法:

  1. 删除 [JsonPropertyAttribute]
  2. 完全移除 setter 并引入支持字段

只有这两个选项吗?

编辑

我为只读属性添加了支持字段。不确定,但我想我在 Json.Net 中发现了一个错误。当只有 getter 存在时,序列化程序会将属性视为不存在,即使指定的名称属性与 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();
}
}

输出

*** Extension data ***

binding_type == OneWay

最佳答案

Json.Net 在使用 [JsonProperty] 属性标记时访问私有(private)成员的事实实际上是设计使然。此功能的存在是为了使 Json.Net 能够用于序列化/反序列化对象的内部状态(例如,持久化它),而无需公开该状态的公共(public)接口(interface)。
来自documentation :

JsonPropertyAttribute

JsonPropertyAttribute has a number of uses:

  • By default the JSON property will have the same name as the .NET property. This attribute allows the name to be customized.

  • Indicates that a property should be serialized when member serialization is set to opt-in.

  • Includes non-public properties in serialization and deserialization.

  • Customize type name, reference, null and default value handling for the property value.

  • Customize the property's collection items JsonConverter, type name handing and reference handling.

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

您已经提到了几种可能性,我将添加第三种可能性:

  1. 删除[JsonPropertyAttribute]
  2. 完全移除 setter 并引入支持字段
  3. 实现自定义 JsonConverter为你的类(class)

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

第一个选项,即删除属性,不会完全满足您的需求。虽然它会阻止字段被反序列化,但您将不得不接受在序列化期间写入 JSON 的原始属性名称。

第三个选项是编写一个转换器,让您可以完全控制类的序列化和反序列化方式。您可以更改属性名称,省略属性,包括甚至不在类中的其他信息,等等。它们并不难写;但是,如果您真正需要的只是一个简单的支持字段来解决您的问题,那么转换器在这里可能有点过分了。也就是说,如果您真的对此选项感兴趣,我很乐意提供一个简单的示例。请告诉我。

编辑

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

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

关于c# - 使用 JsonIgnoreAttribute 标记私有(private) setter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22489595/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com