十倍程序员 | 使用 Source Generator 将 JSON 转换成 C# 类

目录

前言

实现原理

解析 JSON 字符串

匹配 C# 类型

生成 C# 类代码

Source Generator

使用

总结


 

前言

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

执行完成后,它会将生成的代码放在打开的的代码窗口中。

但是,如果有多个 JSON 字符串需要转换,这个过程非常繁琐,而且容易出错。

本文将介绍如何使用 Source Generator 将 JSON 字符串转换成 C# 类。

实现原理

解析 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: https://github.com/feiyun0112/MyIO.ParseJsonAsClass.SourceGenerator

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用C# Newtonsoft Json通过json数据,解码json生成用于保存数据json,通过json生成代码,支持子 自动 如 [{"itemsize":437,"pageId":1,"erpNickShopObj":null,"itemjbxx":[{"num":94628,"numIid":40239293981,"outerId":"异常1元连接","picUrl":"http://img04.taobaocdn.com/bao/uploaded/i4/TB1rdpFGXXXXXc5XFXXXXXXXXXX_!!1-item_pic.gif","price":"1.00","title":"[Enni.kr]<恩妮韩品>补邮费/订单异常关闭专拍连接","volume":0},{"num":65592,"numIid":36048181106,"outerId":"爱茉莉沐浴露套装200ml*3","picUrl":"http://img03.taobaocdn.com/bao/uploaded/i3/516137599/TB21kzXXVXXXXcUXXXXXXXXXXXX_!!516137599.jpg","price":"52.00","title":"韩国进口爱茉莉happybath 沐浴露 柠檬 玫瑰 薰衣草 200ml*3套装","volume":0},{"num":59765,"numIid":38272119734,"outerId":"7难题牙膏 绿款","picUrl":"http://img01.taobaocdn.com/bao/uploaded/i1/516137599/TB2xDbXXVXXXXbbXXXXXXXXXXXX_!!516137599.jpg","price":"9.90","title":"韩国进口LG贝瑞奥/倍瑞奥7难题解决牙膏7功能合一强健120G绿色","volume":0},{"num":59764,"numIid":38288409657,"outerId":"黄金皂2件套礼盒","picUrl":"http://img04.taobaocdn.com/bao/uploaded/i4/516137599/TB2XBbXXVXXXXbKXXXXXXXXXXXX_!!516137599.jpg","price":"90.00","title":"包邮 韩国纯金皂 24K金美容皂 天然特效美容黄金皂 2件套装 礼盒","volume":0},{"num":59763,"numIid":38272395230,"outerId":"7难题牙膏 蓝款","picUrl":"http://img02.taobaocdn.com/bao/uploaded/i2/516137599/TB204vXXVXXXXa5XpXXXXXXXXXX_!!516137599.jpg","price":"9.90","title":"韩国LG 贝瑞奥/倍瑞奥7难题解决牙膏 7功能合一 原味 120G 蓝色","volume":0},{"num":59758,"numIid":38278150798,"outerId":"9928牙膏绿色款","picUrl":"http://img03.taobaocdn.com/bao/uploaded/i3/516137599/TB2KDDXXVXXXXaEXXXXXXXXXXXX_!!516137599.jpg","price":"9.90","title":"韩国 LG贝瑞奥/倍瑞奥9928牙膏 强齿美白牙膏 120G 绿色","volume":0},{"num":59751,"numIid":38288605749,"outerId":"9928牙膏蓝色款","picUrl":"http://img04.taobaocdn.com/bao/uploaded/i4/516137599/TB2n9HXXVXXXXbxXXXXXXXXXXXX_!!516137599.jpg","price":"9.90","title":"韩国 LG 倍瑞奥 9928 牙膏 抗菌 牙龈护理 防蛀牙固定牙齿 120g","volume":0},{"num":59741,"numIid":38301128090,"outerId":"9928牙膏红色款","picUrl":"http://img01.taobaocdn.com/bao/uploaded/i1/516137599/TB2PATXXVXXXXcHXXXXXXXXXXXX_!!516137599.jpg","price":"9.90","title":"韩国 LG贝瑞奥/倍瑞奥9928牙膏 消炎

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值