System.Text.Json 将字典序列化为数组

2023-12-22

是否可以使用 System.Text.Json 将字典序列化(和反序列化)为数组?

代替{ "hello": "world" }我需要将我的字典序列化为{ "key": "hello", "value": "world" }最好不必在我的类的字典属性上设置属性。

使用 newtonsoft.json 可以这样:

class DictionaryAsArrayResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        if (objectType.GetInterfaces().Any(i => i == typeof(IDictionary) || 
           (i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>))))
        {
            return base.CreateArrayContract(objectType);
        }

        return base.CreateContract(objectType);
    }
}

您可以使用JsonConverterFactory https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverterfactory制造特定的JsonConverter<T> https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverter-1对于要序列化为数组的每个字典类型。这是一个这样的转换器,适用于实现的每个类IDictionary<TKey, TValue>:

public class DictionaryConverterFactory : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        return typeToConvert.IsClass && typeToConvert.GetDictionaryKeyValueType() != null && typeToConvert.GetConstructor(Type.EmptyTypes) != null;
    }

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        var keyValueTypes = typeToConvert.GetDictionaryKeyValueType();
        var converterType = typeof(DictionaryAsArrayConverter<,,>).MakeGenericType(typeToConvert, keyValueTypes.Value.Key, keyValueTypes.Value.Value);
        return (JsonConverter)Activator.CreateInstance(converterType);
    }
}

public class DictionaryAsArrayConverter<TKey, TValue> : DictionaryAsArrayConverter<Dictionary<TKey, TValue>, TKey, TValue>
{
}

public class DictionaryAsArrayConverter<TDictionary, TKey, TValue> : JsonConverter<TDictionary> where TDictionary : class, IDictionary<TKey, TValue>, new()
{
    struct KeyValueDTO
    {
        public TKey Key { get; set; }
        public TValue Value { get; set; }
    }

    public override TDictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var list = JsonSerializer.Deserialize<List<KeyValueDTO>>(ref reader, options);
        if (list == null)
            return null;
        var dictionary = typeToConvert == typeof(Dictionary<TKey, TValue>) ? (TDictionary)(object)new Dictionary<TKey, TValue>(list.Count) : new TDictionary();
        foreach (var pair in list)
            dictionary.Add(pair.Key, pair.Value);
        return dictionary;
    }

    public override void Write(Utf8JsonWriter writer, TDictionary value, JsonSerializerOptions options)
    {
        JsonSerializer.Serialize(writer, value.Select(p => new KeyValueDTO { Key = p.Key, Value = p.Value }), options);
    }
}

public static class TypeExtensions
{
    public static IEnumerable<Type> GetInterfacesAndSelf(this Type type)
    {
        if (type == null)
            throw new ArgumentNullException();
        if (type.IsInterface)
            return new[] { type }.Concat(type.GetInterfaces());
        else
            return type.GetInterfaces();
    }

    public static KeyValuePair<Type, Type>? GetDictionaryKeyValueType(this Type type)
    {
        KeyValuePair<Type, Type>? types = null;
        foreach (var pair in type.GetDictionaryKeyValueTypes())
        {
            if (types == null)
                types = pair;
            else
                return null;
        }
        return types;
    }

    public static IEnumerable<KeyValuePair<Type, Type>> GetDictionaryKeyValueTypes(this Type type)
    {
        foreach (Type intType in type.GetInterfacesAndSelf())
        {
            if (intType.IsGenericType
                && intType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
            {
                var args = intType.GetGenericArguments();
                if (args.Length == 2)
                    yield return new KeyValuePair<Type, Type>(args[0], args[1]);
            }
        }
    }
}

然后将工厂添加到JsonSerializerOptions.Converters https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.converters?System_Text_Json_JsonSerializerOptions_Converters本地如下:

var options = new JsonSerializerOptions
{
    Converters = { new DictionaryConverterFactory() },
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};

var json = JsonSerializer.Serialize(dictionary, options);

var dictionary2 = JsonSerializer.Deserialize<TDictionary>(json, options);

或者在 ASP.NET Core 中全局使用,如下所示如何在asp.net core 3中设置json序列化器设置? https://stackoverflow.com/q/58392039/3744182:

services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.Converters.Add(new DictionaryConverterFactory());
    options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});

底层的单独转换器DictionaryAsArrayConverter<TKey, TValue>如果只想将某些字典类型序列化为数组,也可以直接使用。

Notes:

  • JsonSerializer目前不尊重PropertyNamingPolicy https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.propertynamingpolicy序列化时KeyValuePair<TKey, TValue> (see 问题 #1197 https://github.com/dotnet/runtime/issues/1197)所以我不得不介绍一个KeyValueDTO得到外壳"key" and "value"按照你的问题的要求。

  • 我没有实现非通用转换器IDictionary类型。这可以作为答案的延伸来完成。

  • 有关转换器工厂模式的更多信息,请参阅如何在 .NET 中编写用于 JSON 序列化的自定义转换器:示例工厂模式转换器 https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#sample-factory-pattern-converter

  • 类型相当于DefaultContractResolver in System.Text.Json -- JsonClassInfo https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs and JsonPropertyInfo https://github.com/dotnet/corefx/blob/master/src/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs -- are internal。有一个开放的增强功能System.Text.Json 中的 DefaultContractResolver 的等效项 #42001 https://github.com/dotnet/corefx/issues/42001要求公共同等的。

演示小提琴here https://dotnetfiddle.net/0ApBYW.

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

System.Text.Json 将字典序列化为数组 的相关文章

  • 具有子列表属性映射问题的自动映射器

    我有以下型号 Models public class Dish Required public Int64 ID get set Required public string Name get set Required public str
  • 迭代变量并查找特定类型实例的技术

    我想迭代进程中内存中的变量 通过插件动态加载 并查找特定类型的实例 以前我可以找到特定类型 或内存中的所有类型 我可以创建类型的实例 我可以获取作为不同类型的字段包含的实例 但我无论如何都不知道只是 搜索 特定类型的实例 一种方法是使用 W
  • 以编程方式检查页面是否需要基于 web.config 设置进行身份验证

    我想知道是否有一种方法可以检查页面是否需要基于 web config 设置进行身份验证 基本上如果有这样的节点
  • 如何创建可以像 UserControl 一样编辑的 TabPage 子类?

    我想创建一个包含一些控件的 TabPage 子类 并且我想通过设计器来控制这些控件的布局和属性 但是 如果我在设计器中打开子类 我将无法像在 UserControl 上那样定位它们 我不想创建一个带有 UserControl 实例的 Tab
  • 对齐 GridView 中的行值

    我需要在 asp net 3 5 中右对齐 gridview 列中的值 我怎样才能做到这一点
  • C++ 异步线程同时运行

    我是 C 11 中线程的新手 我有两个线程 我想让它们同时启动 我可以想到两种方法 如下 然而 似乎它们都没有按照我的预期工作 他们在启动另一个线程之前启动一个线程 任何提示将不胜感激 另一个问题是我正在研究线程队列 所以我会有两个消费者和
  • 如何从网站下载 .EXE 文件?

    我正在编写一个应用程序 需要从网站下载 exe 文件 我正在使用 Visual Studio Express 2008 我正在使用以下代码 private void button1 Click object sender EventArgs
  • 在 2D 中将一个点旋转另一个点

    我想知道当一个点相对于另一个点旋转一定角度时如何计算出新的坐标 我有一个块箭头 想要将其相对于箭头底部中间的点旋转角度 theta 这是允许我在两个屏幕控件之间绘制多边形所必需的 我无法使用和旋转图像 从我到目前为止所考虑的情况来看 使问题
  • 基于xsd模式生成xml(使用.NET)

    我想根据我的 xsd 架构 cap xsd 生成 xml 文件 我找到了这篇文章并按照说明进行操作 使用 XSD 文件生成 XML 文件 https stackoverflow com questions 6530424 generatin
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • 如何在c#中的内部类中访问外部类的变量[重复]

    这个问题在这里已经有答案了 我有两个类 我需要声明两个类共有的变量 如果是嵌套类 我需要访问内部类中的外部类变量 请给我一个更好的方法来在 C 中做到这一点 示例代码 Class A int a Class B Need to access
  • 将构建日期放入“关于”框中

    我有一个带有 关于 框的 C WinForms 应用程序 我使用以下方法将版本号放入 关于 框中 FileVersionInfo GetVersionInfo Assembly GetExecutingAssembly Location F
  • 当模板类不包含可用的成员函数时,如何在编译时验证模板参数?

    我有以下模板struct template
  • 将代码拆分为标头/源文件

    我从 Asio 的示例页面中获取了以下代码 class tcp connection public boost enable shared from this
  • 剪贴板在 .NET 3.5 和 4 中的行为有所不同,但为什么呢?

    我们最近将一个非常大的项目从 NET Framework 3 5 升级到 4 最初一切似乎都工作正常 但现在复制粘贴操作开始出现错误 我已经成功制作了一个小型的可复制应用程序 它显示了 NET 3 5 和 4 中的不同行为 我还找到了一种解
  • 使用 C# 从 DateTime 获取日期

    愚蠢的问题 给定日期时间中的日期 我知道它是星期二 例如我如何知道它的 tue 2 和 mon 1 等 Thanks 您正在寻找星期几 http msdn microsoft com en us library system datetim
  • 双精度类型二维多维数组的 pinvoke 编组作为 c# 和 c++ 之间的输入和输出

    我有以下我正在尝试解决的双物质类型的 2d 多维数组的 c 和 c pinvoke 编组 我已经查看了以下热门内容以获得我目前拥有的内容使用双精度数组进行 P Invoke 在 C 和 C 之间编组数据 https stackoverflo
  • 用于 C# XNA 的 Javascript(或类似)游戏脚本

    最近我准备用 XNA C 开发另一个游戏 上次我在 XNA C 中开发游戏时 遇到了必须向游戏中添加地图和可自定义数据的问题 每次我想添加新内容或更改游戏角色的某些值或其他内容时 我都必须重建整个游戏或其他内容 这可能需要相当长的时间 有没
  • 是否可以在 C# 中强制接口实现为虚拟?

    我今天遇到了一个问题 试图重写尚未声明为虚拟的接口方法的实现 在这种情况下 我无法更改接口或基本实现 而必须尝试其他方法 但我想知道是否有一种方法可以强制类使用虚拟方法实现接口 Example interface IBuilder
  • 错误:无效使用不完整类型“类 Move”/未定义对 Move::NONE 的引用

    拜托 我不知道为什么这个简单的代码被拒绝 它给了我 2 个编译错误 请帮帮我 I use 代码 块 20 03 我的编译器是GNU GCC 移动 hpp class Move public Move Move int int public

随机推荐

  • 32位机器如何处理大于2^32的数字?

    I am trying to understand how calculations involving numbers greater than 232 happen on a 32 bit machine C code cat size
  • 部分类调试

    我已经为我的 xsd 自动生成的类创建了一个部分类 问题在于调试这个部分类 无法识别断点或者编译器不会在分部类中设置的断点处中断 Autogenerated class by xsd exe public partial class Cla
  • 如何使用 Rust 合并两个 JSON 对象?

    我有两个 JSON 文件 JSON 1 title This is a title person firstName John lastName Doe cities london paris JSON 2 title This is an
  • 如何获取 TFS WIQL 项目的所有用户以及团队迭代?

    我想让所有用户在项目中进行迭代 假设项目 Precient 有 9 个不同的用户 进行了 20 次迭代 所以我希望不同的用户具有项目中的所有迭代WIQL C 这与问题有关 WIQL 查询获取项目中的所有团队和用户 https stackov
  • IE9 忽略某些页面的 CSS?

    我有不同的网站提供服务 基本上运行相同的代码 一个页面可以正确呈现 而另一页面似乎没有可用的 CSS 当我打开损坏页面的 IE9 开发者控制台时 我看到 SEC7113 CSS was ignored due to mime type mi
  • 在在线正则表达式测试器中工作时,正则表达式无法在 Angular Validators.pattern() 中工作

    我已经在 Regex101 com 上编写并严格测试了正则表达式 但是当实现到我的 FormControl Validators pattern 方法中时 它显示了意外的行为 这是用于要邮寄的包裹的宽度输入 仅限正值 最多 2 位小数 最小
  • 从 npm 下载一个包作为 tar (不是将其安装到模块中)

    是否有一些 URL 可以让我从 npm 下载给定的包 作为 tarball 或其他东西 我需要最初上传到 npm 的确切文件 Using npm install例如 获取不同的生成的 package json 我想要已发布的确切原始文件集
  • 将 Gradle 5.3.1 升级到 6.5。旧版本下载依赖项正常,但在 6.5 上失败

    我已将问题简化为一个非常简单的项目 该项目声明了对从客户的工件实例提供的模块工件的模块依赖关系 这在 5 3 1 中运行良好 从下面的日志中可以看出 有一行表明 DefaultExternalResourceArtifactResolver
  • java 中的 Thread.sleep() 与同步

    当 Thread sleep 10000 被调用时 当前线程将进入睡眠状态 如果在同步方法中调用Thread sleep 10000 那么在此期间其他线程是否可以执行 如果你这样做Thread sleep 10000 在同步方法中或阻止您d
  • 使用 CakePHP Auth 时出现未定义方法 stdClass::user() 错误

    我对 CakePHP 相当陌生 正在使用 Auth 组件构建一个网站 有几次我尝试用这个组件做一些导致错误的事情 Fatal error Call to undefined method stdClass user in ftphome s
  • 是否可以在 Android 上创建符号链接?

    我想知道在 android 中是否可以从我的 android 应用程序创建符号链接 因为我想使用 sdcard 创建我的应用程序的文件夹 数据的符号链接 我不是 android 方面的专家 但我通常使用 Java nio File File
  • 如何自定义QCalendarWidget?

    我正在尝试将一些样式表应用到我的QCalendarWidget 我已经做了一些改变 这是我现在的代码 QCalendarWidget QWidget background color magenta color green QCalenda
  • multinom() 默认情况下如何处理 NA 值?

    当我跑步时multinom say Y X1 X2 X3 如果对于某一特定行X1 is NA 即缺失 但是Y X2 and X3全部都有值 是否会丢弃整行 就像 SAS 中那样 如何处理缺失值multinom 这是一个简单的例子 来自 mu
  • 如何将 Docker Hub 镜像拉取到 Google Cloud Run?

    我正在尝试将 Docker 映像拉入 Google Cloud Run 我发现我可能需要先将其拉到 Google 容器注册表 但我可以以某种方式避免它吗 另外 我宁愿直接从源头获取它以使其保持最新 我查看了该项目 最后在 Cloud Run
  • Java 对象、更改字段侦听器、设计模式

    有一个类 public class MyClass private String field1 private String field2 private String field3 getters setters 然后我们更新一些字段 M
  • 尽管 flex-basis: 0 [重复],Flexbox 项目的宽度并不相等

    这个问题在这里已经有答案了 我在 Flexbox 中有 4 列 我希望它们的宽度相等 那个有overflow hidden比其他人占据更多的位置 而我无法修复它 在我看来 我遇到了与这篇文章中所述相同的问题 Flexbox 和溢出隐藏无法正
  • 使用“从浏览器中单击”按钮打开客户端的桌面应用程序 - Python/HTML [重复]

    这个问题在这里已经有答案了 我想打开桌面应用程序 例如 记事本 Powerpoint Putty 附上它在共享点上如何工作的图像 随附的示例图像显示了如何通过单击按钮打开 Microsoft Teams 我需要这个精确的复制品 单击 打开
  • Visual Studio 2015 调试并继续

    我们将环境从 Visual Studio 2008 更改为 2015 更新 1 现在我们遇到了一些奇怪的调试行为 当我们遇到断点并更改一些代码并继续时 我们无法再在快速监视或立即窗口中看到某些类型的变量内容 例如数据表 图像 A type
  • 如何测试 PHP 程序? [复制]

    这个问题在这里已经有答案了 有没有办法测试程序代码 我一直在研究 PHPUnit 它似乎是创建自动化测试的好方法 然而 它似乎是面向面向对象的代码 是否有过程代码的替代方案 或者我应该在尝试测试网站之前将网站转换为面向对象 这可能需要一段时
  • System.Text.Json 将字典序列化为数组

    是否可以使用 System Text Json 将字典序列化 和反序列化 为数组 代替 hello world 我需要将我的字典序列化为 key hello value world 最好不必在我的类的字典属性上设置属性 使用 newtons