【问题标题】:Json.Net ignore serialized private fields in UnityJson.Net 忽略 Unity 中的序列化私有字段
【发布时间】:2022-01-06 14:19:34
【问题描述】:

我想从 json 序列化中忽略序列化的私有字段,但似乎 [JsonIgnore] 仅适用于 public 字段,不适用于 [SerializeField] private 字段。有没有其他方法可以忽略这些字段?

这是一个示例类:

using UnityEngine;
using Newtonsoft.Json;

[JsonObject(MemberSerialization.OptIn)]
public class ExampleObject : MonoBehaviour {
    [JsonProperty]
    private string property = "Property";

    [JsonIgnore]
    [SerializeField]
    private string ignored = "Ignored";
}

输出

{"property":"Property","ignored":"Ignored"}

它仍然将ignored 字段序列化为json,即使我在类上使用[JsonObject(MemberSerialization.OptIn)] 并在private 字段上使用[JsonIgnore]。

MemberSerialization.OptIn 这么说

“只有标有JsonPropertyAttribute 或System.Runtime.Serialization.DataMemberAttribute 的成员才会被序列化”

,但它似乎也包含SerializeField 属性。

编辑:我正在使用 JilleJr Newtonsoft.Json-for-Unity (github link) 和 JilleJr Newtonsoft.Json-for-Unity.Converters(github link)

【问题讨论】:

  • [SerializeField]属性的作用是什么?
  • 这是一个很好的问题。我在文档中搜索了here,但它只显示了一个公共属性。 Here 在这篇文章中,您可以通过搜索属性的类型来了解该人如何使用 IsIgnored 方法。那个或this 的帖子可能会有所帮助。
  • 如果您想排除私有字段,那么为什么不使用默认的退出行为呢? 默认情况下,类型的属性以退出模式序列化。这意味着所有带有 getter 的公共字段和属性都会自动序列化为 JSON,并且不应该序列化的字段和属性会通过在其上放置 JsonIgnoreAttribute 来选择退出。要序列化私有成员,可以将 JsonPropertyAttribute 放在私有字段和属性上 - Source
  • 您使用的是来自 nuget.org/packages/Newtonsoft.Json 的 Json.NET 还是某个 Unity 特定的端口?如果是这样,什么端口/版本?如果我只是序列化具有与ExampleObject 相同属性的 DTO,则不会序列化 ignored,请参阅dotnetfiddle.net/ZeOSf7。这让我相信您使用的是针对 Unity 进行了调整的 Json.NET 版本,因为原版 Json.NET 不知道 [SerializeField]。
  • @Serge 为什么不呢? ^^ 这就是 Unity Inspector 的工作方式,通常很有意义的是,字段是私有的但在 Inspector => 封装中暴露。该字段只能通过 Inspector 进行调整,不能以其他方式访问

标签: c# json unity3d json.net


【解决方案1】:

问题是您使用的 Json.NET 端口JilleJr Newtonsoft.Json-for-Unity.Converters 包含一个自定义合约解析器UnityTypeContractResolver,其中包括标记为[SerializeField] 的成员即使还标记为[JsonIgnore]。来自source:

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
   JsonProperty jsonProperty = base.CreateProperty(member, memberSerialization);

   // A check for member.GetCustomAttribute<JsonIgnoreAttribute>() is missing in the following line:
   if (member.GetCustomAttribute<SerializeField>() != null) 
   {
       jsonProperty.Ignored = false;
       jsonProperty.Writable = CanWriteMemberWithSerializeField(member);
       jsonProperty.Readable = CanReadMemberWithSerializeField(member);
       jsonProperty.HasMemberAttribute = true;
   }

   return jsonProperty;
}

如果您不希望这样,则需要将此合同解析器子类化并纠正行为:

public class FixedUnityTypeContractResolver : Newtonsoft.Json.UnityConverters.UnityTypeContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
       JsonProperty jsonProperty = base.CreateProperty(member, memberSerialization);

       if (!jsonProperty.Ignored && member.GetCustomAttribute<Newtonsoft.Json.JsonIgnoreAttribute>() != null) 
           jsonProperty.Ignored = true;

       return jsonProperty;
    }
}

然后序列化如下:

// Cache and reuse the contract resolver throughout your project to improve performance.
static Newtonsoft.Json.Serialization.IContractResolver _resolver = new FixedUnityTypeContractResolver ();

var settings = new JsonSerializerSettings 
{
    ContractResolver = _resolver,
};
JsonConvert.SerializeObject(this, settings);

【讨论】:

  • 注意 - 没有经过测试,因为我目前没有安装 Unity。
  • 感谢您的回答,现在使用[JsonIgnore] 属性时可以正常工作。您知道是否有任何方法可以使[JsonObject(MemberSerialization.OptIn)] 与该系统一起工作,这样我就不必将[JsonIgnore] 添加到每个序列化的私有字段中?你不需要写一个完整的答案,你可以给我指出正确的方向,这样我就知道在哪里寻找答案。 Json 序列化对我来说仍然很新,因为我只有大约 20 小时的 Json 经验。
  • @Crossoni - 你真的想要消除自动包含[SerializeField] 成员的功能,而是回退到 Json.NET 的默认行为吗?
  • 我实际上希望私有 SerializeField 字段与公共字段完全一样工作,因此如果我使用 MemberSerialization.OptIn 他们需要用 [JsonProperty] 标记才能被包含,如果我使用MemberSerialization.OptOut 默认情况下它们将包含在 json 中。我尝试删除 Unity.Converters 包,似乎我现在在我的项目中真的不需要它,但我以后可能需要它。如果没有它,我需要用[JsonProperty] 标记所有私有SerializeField 字段,否则它们不包含在json 中,这可以解决问题。
猜你喜欢
  • 2015-11-07
  • 1970-01-01
  • 2016-08-27
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多