十倍程序員 | 使用 Source Generator 將 JSON 轉換成 C# 類

前言

有時候,我們需要將通過 WebAPI 接收 JSON 字符串轉換成 C# 代碼。Visual Studio 提供了一個功能菜單可以輕松實現:

273a56b09fed9f3c0913d4e5796b1bb4.png

執行完成后,它會將生成的代碼放在打開的的代碼窗口中。

但是,如果有多個 JSON 字符串需要轉換,這個過程非常繁瑣,而且容易出錯。

本文將介紹如何使用 Source Generator 將 JSON 字符串轉換成 C# 類。

實現原理

解析 JSON 字符串

首先,我們需要解析 JSON 字符串,分析它的結構,再對應到 C# 類。這里,我們使用 System.Text.Json 庫。

通過JsonDocument.Parse方法解析 JSON 字符串,它將返回一個JsonDocument對象:

using?var?jsonDocument?=?JsonDocument.Parse(json);

下圖很好的說明了JsonDocument的結構:

93d361b51e745dac715661a8007e062f.png

  • 一個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
  1. 在項目中添加一個 JSON 文件

{"code":?200,"msg":?"ok","obj":{"a":1,"subObj":{"a":1}},"data":?["1","2"],"array":?[{"a":1.0},{"a":null}]
}
  1. 在項目中添加一個 C# 文件

using?MyIO;
namespace?ConsoleApp1
{[ParseJsonAsClass("sample.txt")]internal?partial?class?Class1{?}
}

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

  1. 編譯項目

f74e2d0b6a15c339ab40585ec5920938.jpeg

總結

相關源代碼已上傳到 GitHub: https://github.com/feiyun0112/MyIO.ParseJsonAsClass.SourceGenerator,點擊“閱讀原文”可直達,歡迎 Star。

添加微信號【MyIO666】,邀你加入技術交流群

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282364.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282364.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282364.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Delphi對話框初始地址InitialDir

我的電腦&#xff1a;SaveDialog1.InitialDir : ::{20D04FE0-3AEA-1069-A2D8-08002B30309D};// My Computer {20D04FE0-3AEA-1069-A2D8-08002B30309D}// Network Neighborhood {208D2C60-3AEA-1069-A2D7-08002B30309D}// Recycled {645FF040-5081-101B-9F08-00AA002F954E} 另外…

[python] 解決pip install download速度過慢問題 更換豆瓣源

""" python建立pip.ini.py 2016年4月30日 03:35:11 codegay """import osini"""[global] index-url https://pypi.doubanio.com/simple/ [install] trusted-hostpypi.doubanio.com """ pippathos.environ["…

Maven組件通過命令上傳本地和私有倉庫

安裝本地包到本地倉庫&#xff1a;mvn install:install-file -DgroupIdcom.xxx -DartifactIdmqtt-server-client -Dversion1.0.1 -Dpackagingjar -DfileE:\__vdt\MVVP\mqtt-server-client-1.0.1.jar -DpomFileE:\__vdt\MVVP\pom.xml安裝本地包到私有倉庫&#xff1a;mvn deploy…

Nginx -靜態資源Web服務

一、靜態資源類型 注&#xff1a;非服務器動態生成的文件 1、瀏覽器端渲染 HTML、css、js 2、圖片 jpeg、gif、png 3、視頻 flv、MPEG 4、文件 TXT、等任意下載文件二、靜態資源服務配置1、配置語法-文件讀取 syntax&#xff1a;sendfile on|off default&#xff1a;sendfi…

微軟Microsoft Azure 機器學習工作室的案例之Image Classification using DenseNet

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;10分鐘)Microsoft Azure Machine Learning Studio是微軟強大的機器學習平臺&#xff0c;在設計器中&#xff0c;微軟內置了15個場景案例&#xff0c;但網上似乎沒有對這15個案例深度刨析的分析資料&#xff0c;所以我…

java小基礎之instanceof運算符

instanceof主要用來判斷一個類是否實現了某個接口&#xff0c;或者判斷一個實例對象是否屬于一個類。 1. 判斷一個對象是否屬于一個類 boolean result p instanceof Student; 2. 對象類型強制轉換前的判斷 Person p new Student(); //判斷對象p是否為Student類的實例 if(p in…

音樂分類

代碼&#xff1a; 1 import numpy as np2 from scipy import fft3 from scipy.io import wavfile4 from sklearn.linear_model import LogisticRegression5 import random6 """7 使用logistic regression處理音樂數據&#xff0c;音樂數據訓練樣本的獲得是使…

Problem C: 類的初體驗(III)

Description 定義一個類Data&#xff0c;只有一個double類型的屬性和如下4個方法&#xff1a; 1. 缺省構造函數&#xff0c;將屬性初始化為0&#xff0c;并輸出“Initialize a data 0”。 2. 帶參構造函數&#xff0c;將屬性初始化為指定參數&#xff0c;并輸出“Initialize…

Nginx- 實現跨域訪問

一、什么是跨域 跨域&#xff1a;由于瀏覽器的同源策略&#xff0c;即屬于不同域的頁面之間不能相互訪問各自的頁面內容。詳細見下表&#xff1a; 注&#xff1a;同源策略&#xff0c;單說來就是同協議&#xff0c;同域名&#xff0c;同端口 URL說明是否允許通信http://www.a…

不管對不對,先把鬧鐘關了再說

小榆提前關閉早上鬧鐘&#xff0c;幾乎工作日的早晨都是被這魔怔的鈴聲給拉扯醒&#xff0c;無論有多么不愿還是痛苦&#xff0c;可對這鬧鐘也無可奈何&#xff0c;就算一時果斷掐掉接下來是另一回麻煩事。最后一天&#xff0c;已經顧不得多少&#xff0c;沒什么令人懼怕的人或…

pycharm(windows)安裝及其設置中文菜單

pycharm&#xff08;windows&#xff09;安裝及其設置中文菜單 1.下載 在官網&#xff08;http://www.jetbrains.com/pycharm/download/#sectionwindows&#xff09;進行下載 或者到百度云進行下載 專業版&#xff1a;鏈接&#xff1a;http://pan.baidu.com/s/1bSSRds 密碼&…

Tomcat定義虛擬主機案例

Tomcat定義虛擬主機案例 作者&#xff1a;尹正杰 版權聲明&#xff1a;原創作品&#xff0c;謝絕轉載&#xff01;否則將追究法律責任。 一.準備環境 1>.創建web程序的根目錄 [rootyinzhengjie ~]# mkdir -pv /home/yinzhengjie/data/www/webapps/ROOT mkdir: created direc…

node服務成長之路

我們的系統也從第一代平臺開始到現在第四代平臺更換中&#xff0c;對這四代平臺做一個簡單的介紹&#xff1a; 第一代平臺&#xff0c;主要是集中式&#xff0c;以快速上線為目的&#xff1b;第二代平臺主要是分布式改造&#xff0c;緩解各服務壓力&#xff1b;第三代平臺主要做…

將域名綁定到ip上,并實現訪問不同二級子域名對應不同目錄

一、將域名綁定到ip上1、環境介紹&#xff1a;阿里云服務器ESC&#xff08;美國硅谷&#xff09; 2、購買域名 3、備案 注&#xff1a;由于我買的是美國地區服務器&#xff0c;所以不用備案&#xff0c;如果買的國內服務器&#xff0c;這里需要添加一個備案操作。 4、域名實名認…

ABP vNext微服務架構詳細教程(補充篇)——單層模板(中)

框架搭建2聚合服務這里我們將聚合服務命名為Domain.Core和基礎服務層一致&#xff0c;我們先通過命令創建單層模板項目Domain.Core&#xff0c;這里我們刪除wwwroot、Data、Entities、Localization、ObjectMapping文件夾及其所有子文件&#xff0c;并刪除package.json文件和Ser…

談一談synchronized關鍵詞

1.使用 java中的每一個對象都可以作為synchronized的鎖進行代碼同步&#xff0c;常見的形式 同步代碼塊鎖是synchronized括號內的對象普通成員方法上&#xff0c;鎖是當前的對象&#xff0c;synchronized(this)靜態方法上&#xff0c;鎖是當前類的Class對象2. 原理 synchronize…

系統學習redis之二——redis集群搭建

redis單點部署&#xff1a; 安裝命令&#xff1a; # cd /usr/local/ # wget http://download.redis.io/releases/redis-4.0.1.tar.gz #下載安裝包 # yum -y install gcc psmisc #安裝依賴包 # tar xf redis-4.0.1.tar.gz # cd /usr/lo…

業務技術協同線上化的研發管理實戰

摘要&#xff1a;2017年1月13日舉辦的【云棲計算之旅】線下沙龍第4期研發管理專場&#xff0c;阿里巴巴B2B事業群產品專家代平為大家帶來了題為業務技術協同線上化的研發管理實戰的演講。本文主要從管理產品研發的理念開始談起&#xff0c;著重說明了云效指揮部的六大步驟&…

Linux中寫腳本,同時去開啟我們自己設定的多個服務(含定時腳本實現)

場景介紹&#xff1a; 在Linux中&#xff0c;我們通常開啟服務需要使用systemctl start 服務名 命令&#xff0c;這樣&#xff0c;如果開啟一個服務還好&#xff0c;但是如果同時開啟多個服務&#xff0c;難免會感到麻煩&#xff0c;這時&#xff0c;我們可以自定義一個腳本&a…

Android之利用EventBus進行數據傳遞

在項目中&#xff0c;不可避免的要在兩個頁面之間進行數據的傳遞&#xff0c;就算不傳遞&#xff0c;也需要進行刷新之類的&#xff0c;我們根據Google提供的庫類方法&#xff0c;也是可以做的&#xff0c;主要有廣播broadcastreceiver&#xff0c;startactivity方法或者是appl…