这样的标准上海市疫情防控工作领导小组也好意思发布出来?

人民日报林治波社长发出灵魂拷问:你们是没有常识,还是没有良知?

惨烈的高峰防御战—“圣元春战役”打响!

母子乱伦:和儿子做了,我该怎么办?

一定在信仰的指导下抗击疫情《马克思主义信仰:战胜新冠肺炎疫情的内生力量》

生成图片,分享到微信朋友圈

自由微信安卓APP发布,立即下载! | 提交文章网址
查看原文

使用 Source Generator 将 JSON 转换成 C# 类

My IO 微软开发者MSDN 2022-11-04

点击上方蓝字

关注我们

(本文阅读时间:6分钟)


有时候,我们需要将通过 WebAPI 接收 JSON 字符串转换成 C# 代码。Visual Studio 提供了一个功能菜单可以轻松实现:


执行完成后,它会将生成的代码放在打开的代码窗口中。
但是,如果有多个 JSON 字符串需要转换,这个过程非常繁琐,而且容易出错。本文将介绍如何使用 Source Generator 将 JSON 字符串转换成 C# 类。




微软MVP实验室研究员


张海

微软最有价值专家,主要关注 .NET 相关的技术及解决方案,致力于将个人的输入转变为输出,公众号:My IO






实现原理


▌解析 JSON 字符串

首先,我们需要解析 JSON 字符串,分析它的结构,再对应到 C# 类。这里,我们使用 System.Text.Json 库。通过 JsonDocument.Parse 方法解析 JSON 字符串,它将返回一个 JsonDocument 对象:
using var jsonDocument = JsonDocument.Parse(json);

下图很好的说明了 JsonDocument 的结构:

  • 一个 JsonDocument 由多个 JsonElementJsonProperty 组成

  • 一个 JsonElement 包含多个 JsonProperty

  • 一个 JsonProperty 的值也是一个 JsonElement

通过递归遍历,我们可以解析出 JSON 字符串的结构。

▌匹配 C# 类型

接下来,我们需要将解析出的 JSON 字符串结构,匹配成 C# 类型。这里,我们使用如下代码来存储类和属性信息:

public class ParsedType

        //名称
        public string Name { get; private set; }
        //类型
        public TypeEnum Type { get; private set; }
        //针对 Array 的类型
        public ParsedType InternalType { get; private set; }
        //属性列表
        public IList<PropertyInfo> Properties { get; internal set; }
        //是否是顶级类,用于区分嵌套子类
        public bool IsRoot { get; internal set; }
}

public class PropertyInfo
{
    public string Name { get; private set; }
    public string JsonName { get; private set; }
    public ParsedType Type { get; private set; }
}
▌生成 C# 类代码

匹配出了 C# 类型,生成 C# 类代码就非常容易了。这里,我们使用如下代码:

WriteFileStart(sw,name_space,class_name);

foreach (var type in types)
{
    WriteClass(sw, type);
}

WriteFileEnd(sw);

types 是上一步解析出的 ParsedType 集合。

▌Source Generator

现在,我们需要使用 Source Generator 将完整流程实现。首先,我们定义了一个 Attribute:

const string attributeText = @"using System;

namespace MyIO
{
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class ParseJsonAsClassAttribute : Attribute
    {
        public ParseJsonAsClassAttribute(string fileName)
        {
            FileName = fileName;
        }

        public string FileName { get; set; }
    }
}
"
;

  context.AddSource("MyIO.ParseJsonAsClassAttribute.g", SourceText.From(attributeText, System.Text.Encoding.UTF8));
然后,我们遍历项目中所有声明了ParseJsonAsClassAttribute的类,拿到namesapceclassname 和 JSON 字符串,生成 C# 类代码,然后写到项目中:
foreach (var memberSyntax in memberSyntaxes)
{
    if (memberSyntax is ClassDeclarationSyntax classDeclarationSyntax)
    {
        var name_space = GetNamespace(classDeclarationSyntax);
        var class_name = classDeclarationSyntax.Identifier.ValueText;

        string json = GetJson(classDeclarationSyntax);

        if (json == null)
        {
            continue;
        }

        var sourceText = GenerateSource(name_space, class_name, json);

        if (sourceText != null)
        {
            this.context.AddSource("MyIO.ParseJsonAsClass." + classDeclarationSyntax.Identifier.ValueText + ".g", sourceText);
        }
    }
    this.context.CancellationToken.ThrowIfCancellationRequested();
}





使用


1、在项目中安装 NuGet 包

dotnet add package MyIO.ParseJsonAsClass.SourceGenerator
2、在项目中添加一个 JSON 文件
{
  "code"200,
  "msg""ok",
  "obj":{"a":1,"subObj":{"a":1}},
  "data": [
    "1","2"
  ],
  "array": [
    {"a":1.0},
    {"a":null}
  ]
}
3、在项目中添加一个 C# 文件
using MyIO;
namespace ConsoleApp1
{
    [ParseJsonAsClass("sample.txt")]
    internal partial class Class1
    { 
    }
}

sample.txt 是上一步中添加的 JSON 文件的名称。

4、编译项目


*未经授权请勿私自转载此文章及图片。

欢迎前往 GitHub 获取相关源代码信息。

长按识别二维码

                      


微软最有价值专家(MVP)



微软最有价值专家是微软公司授予第三方技术专业人士的一个全球奖项。29年来,世界各地的技术社区领导者,因其在线上和线下的技术社区中分享专业知识和经验而获得此奖项。MVP是经过严格挑选的专家团队,他们代表着技术最精湛且最具智慧的人,是对社区投入极大的热情并乐于助人的专家。MVP致力于通过演讲、论坛问答、创建网站、撰写博客、分享视频、开源项目、组织会议等方式来帮助他人,并最大程度地帮助微软技术社区用户使用 Microsoft 技术。更多详情请登录官方网站:
https://mvp.microsoft.com/zh-cn


点击「阅读原文」获取相关源代码~

文章有问题?点此查看未经处理的缓存