Json.NET 从自动属性初始值设定项获取默认值

2024-02-26

我想减少字符串Json.NET https://github.com/JamesNK/Newtonsoft.Json使用默认值生成。

我的属性之一如下:

public string Name { get; set; } = "Jennifer";

我已经使用自动属性初始值设定项,因此如果字符串为空,则会填充该字符串。

当使用 Json.NET 进行序列化时,我使用DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate因此只有更改的属性才会被保留。

我知道我可以使用DefaultValueAttribut像这样:

[DefaultValue("Jennifer")]
public string Name { get; set; } = "Jennifer";

但我想知道是否可以跳过此属性并在序列化时使用自动属性初始值作为默认值。


是的,您可以使用自定义来做到这一点ContractResolver比如下面这个。它的工作原理是为每个Type(假设Type是一个类并且有一个可用的默认构造函数),然后设置ShouldSerialize对每个属性进行谓词,根据引用实例检查属性的当前值。如果它们匹配,那么ShouldSerialize返回 false 并且该属性未序列化。

class CustomResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
        if (type.IsClass)
        {
            ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
            if (ctor != null)
            {
                object referenceInstance = ctor.Invoke(null);
                foreach (JsonProperty prop in props.Where(p => p.Readable))
                {
                    prop.ShouldSerialize = instance =>
                    {
                        object val = prop.ValueProvider.GetValue(instance);
                        object refVal = prop.ValueProvider.GetValue(referenceInstance);
                        return !ObjectEquals(val, refVal);
                    };
                }
            }
        }
        return props;
    }

    private bool ObjectEquals(object a, object b)
    {
        if (ReferenceEquals(a, b)) return true;
        if (a == null || b == null) return false;
        if (a is IEnumerable && b is IEnumerable && !(a is string) && !(b is string))
            return EnumerableEquals((IEnumerable)a, (IEnumerable)b);
        return a.Equals(b);
    }

    private bool EnumerableEquals(IEnumerable a, IEnumerable b)
    {
        IEnumerator enumeratorA = a.GetEnumerator();
        IEnumerator enumeratorB = b.GetEnumerator();
        bool hasNextA = enumeratorA.MoveNext();
        bool hasNextB = enumeratorB.MoveNext();
        while (hasNextA && hasNextB)
        {
            if (!ObjectEquals(enumeratorA.Current, enumeratorB.Current)) return false;
            hasNextA = enumeratorA.MoveNext();
            hasNextB = enumeratorB.MoveNext();
        }
        return !hasNextA && !hasNextB;
    }
}

要使用解析器,您需要将其添加到JsonSerializerSettings并将设置传递给SerializeObject像这样的方法:

JsonSerializerSettings settings = new JsonSerializerSettings
{
    ContractResolver = new CustomResolver(),
};
string json = JsonConvert.SerializeObject(yourObject, settings);

这是一个工作演示:https://dotnetfiddle.net/K1WbSP https://dotnetfiddle.net/K1WbSP

关于此解决方案的一些注意事项:

  • 使用该解析器比使用该解析器具有功能优势DefaultValue属性,因为它可以处理复杂的默认值,例如Lists, Dictionaries和子对象(前提是您已正确实现Equals子类的方法)。属性只能处理简单的常量表达式(例如字符串、枚举和其他原语)。但是,如果您需要的只是简单的默认值,请注意,此解析器的性能可能比仅使用属性稍差,因为它需要使用额外的反射来实例化引用对象并比较所有属性值。因此需要进行一些权衡。如果您的 JSON 很小,您可能不会注意到差异。但如果您的 JSON 很大,那么您可能需要做一些基准测试。

  • 您可能想要实现类级选择退出机制(即解析器查找的自定义属性,或者可能是传递给解析器的类名列表),以防遇到以下情况:do希望为某些类序列化默认值,但不序列化其他类。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Json.NET 从自动属性初始值设定项获取默认值 的相关文章

  • 通信对象 System.ServiceModel.Channels.ServiceChannel 不能用于通信

    通信对象System ServiceModel Channels ServiceChannel 无法用于通信 因为它处于故障状态 这个错误到底是什么意思 我该如何解决它 您收到此错误是因为您让服务器端发生 NET 异常 并且您没有捕获并处理
  • 处理 fanart.tv Web 服务响应 JSON 和 C#

    我正在尝试使用 fanart tv Webservice API 但有几个问题 我正在使用 Json Net Newtonsoft Json 并通过其他 Web 服务将 JSON 响应直接反序列化为 C 对象 这里的问题是元素名称正在更改
  • Guid 应包含 32 位数字和 4 个破折号

    我有一个包含 createuserwizard 控件的网站 创建帐户后 验证电子邮件及其验证 URL 将发送到用户的电子邮件地址 但是 当我进行测试运行时 单击电子邮件中的 URL 时 会出现以下错误 Guid should contain
  • try-catch 中未处理的异常

    try list from XElement e in d Descendants wix File where e Attribute Name Value Contains temp Name e Parent Parent Attri
  • 调试内存不足异常

    在修复我制作的小型 ASP NET C Web 应用程序的错误时 我遇到了 OutOfMemoryException 没有关于在哪里查看的提示 因为这是一个编译时错误 如何诊断此异常 我假设这正是内存分析发挥作用的地方 有小费吗 Thank
  • 如何在 VS 中键入时显示方法的完整文档?

    标题非常具有描述性 是否有任何扩展可以让我看到我正在输入的方法的完整文档 我想查看文档 因为我可以在对象浏览器中看到它 其中包含参数的描述和所有内容 而不仅仅是一些 摘要 当然可以选择查看所有覆盖 它可能是智能感知的一部分 或者我不知道它并
  • 转到 C# WPF 中的第一页

    我正在 WPF 中使用导航服务 为了导航到页面 我使用 this NavigationService Navigate new MyPage 为了返回我使用 this NavigationService GoBack 但是如何在不使用的情况
  • 是否有与 C++11 emplace/emplace_back 函数类似的 C# 函数?

    从 C 11 开始 可以写类似的东西 include
  • Xamarin Android:获取内存中的所有进程

    有没有办法读取所有进程 而不仅仅是正在运行的进程 如果我对 Android 的理解正确的话 一次只有一个进程在运行 其他所有进程都被冻结 后台进程被忽略 您可以使用以下代码片段获取当前正在运行的所有 Android 应用程序进程 Activ
  • C# 创建数组的数组

    我正在尝试创建一个将使用重复数据的数组数组 如下所示 int list1 new int 4 1 2 3 4 int list2 new int 4 5 6 7 8 int list3 new int 4 1 3 2 1 int list4
  • std::bind 重载解析

    下面的代码工作正常 include
  • 在 C 中复制两个相邻字节的最快方法是什么?

    好吧 让我们从最明显的解决方案开始 memcpy Ptr const char a b 2 调用库函数的开销相当大 编译器有时不会优化它 我不会依赖编译器优化 但即使 GCC 很聪明 如果我将程序移植到带有垃圾编译器的更奇特的平台上 我也不
  • 过期时自动重新填充缓存

    我当前缓存方法调用的结果 缓存代码遵循标准模式 如果存在 则使用缓存中的项目 否则计算结果 在返回之前将其缓存以供将来调用 我想保护客户端代码免受缓存未命中的影响 例如 当项目过期时 我正在考虑生成一个线程来等待缓存对象的生命周期 然后运行
  • gdb查找行号的内存地址

    假设我已将 gdb 附加到一个进程 并且在其内存布局中有一个文件和行号 我想要其内存地址 如何获取文件x中第n行的内存地址 这是在 Linux x86 上 gdb info line test c 56 Line 56 of test c
  • 运行代码首先迁移更新数据库时出错

    我在迁移到数据库时遇到问题 并且似乎找不到我遇到的错误的答案 System MissingMethodException Method not found System Data Entity Migrations Builders Tab
  • 如何在 GCC 5 中处理双 ABI?

    我尝试了解如何克服 GCC 5 中引入的双重 ABI 的问题 但是 我没能做到 这是一个重现错误的非常简单的示例 我使用的GCC版本是5 2 如您所见 我的主要函数 在 main cpp 文件中 非常简单 main cpp include
  • 过度使用委托对性能来说是一个坏主意吗? [复制]

    这个问题在这里已经有答案了 考虑以下代码 if IsDebuggingEnabled instance Log GetDetailedDebugInfo GetDetailedDebugInfo 可能是一个昂贵的方法 因此我们只想在调试模式
  • 如何打开 Windows 资源管理器窗口并选择特定文件夹

    我有一个 winform 应用程序 这个 winform 应用程序创建了几个文件 我想在我的应用程序中实现 查找目标 功能来显示这些文件 这些文件位于同一文件夹中 看图片 假设我创建了几个文件 C Test 文件夹 该文件夹包含以下文件 C
  • 为什么 Ajax.BeginForm 在 Chrome 中不起作用?

    我正在使用 c NET MVC2 并尝试创建一个 ajax 表单来调用删除数据库记录 RemoveRelation 的方法 删除记录的过程正在按预期进行 删除记录后 表单应调用一个 JavaScript 函数 从视觉效果中删除该记录 Rem
  • 如何创建向后兼容 Windows 7 的缩放和尺寸更改每显示器 DPI 感知应用程序?

    我是 WPF 和 DPI 感知 API 的新手 正在编写一个在 Windows 7 8 1 和 10 中运行的应用程序 我使用具有不同每个显示器 DPI 设置的多个显示器 并且有兴趣将我的应用程序制作为跨桌面配置尽可能兼容 我已经知道可以将

随机推荐