試用 ModVB(一):安裝教程+使用 JSON 常量和 JSON 模式匹配
前排提醒:閱讀此文章并充分嘗試 ModVB 的新語法需要較長的時間。對于程序員而言,如果你工作時不用 VB,則最好避免在上班時間看,以免被領導認為你在長時間摸魚。
什么是 ModVB
ModVB 是一個免費和獨立的 VB.NET “mod”,裝一個 VSIX 和對應的 NuGet 包就能用新功能。
其中 mod 的意思包含:修改版(modified),現代(modern),以及 取模運算(modulo) (VB + ModVB) Mod VB = ModVB。
關于 ModVB 的作者
Anthony D. Green 在微軟的托管編程語言團隊有八年工作經驗。大多時候是 Roslyn 編譯器團隊的項目群 / 項目集經理(Program Manager)。他從 13 歲起從 VB4 開始編程,在發布 ModVB 的第一個公測版本時 37 歲。
安裝過程
注:編寫此文章時,Visual Studio 2022 版本為 17.3.2,插件版本為 0.0.1.0。示例中使用的操作系統是 Windows 10 x64 專業版 21H2,簡體中文。
創建 Visual Studio 2022 的獨立環境
此步驟用于隔離裝了 ModVB 的環境和沒裝的環境,以便插件的分別管理。
- 啟動 Visual Studio 2022 開發人員命令提示符
- 執行命令
devenv /rootSuffix ModVB - 建議為 ModVB 創建一個快捷方式,例如
"C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe" /rootSuffix ModVB
添加 ModVB 的 MyGet VSIX 源
從菜單上打開 工具→選項,左側找到 環境→擴展
添加其他擴展庫:
- 名稱: ModVB
- 鏈接:
https://www.myget.org/F/modvb/vsix/
點擊應用(Apply)

添加 ModVB 的 NuGet 源
還是在選項對話框里。左側找到NuGet包管理器→程序包源
在右邊添加新的包源并且確保它已經打勾
- 名稱: ModVB
- 源:
https://www.myget.org/F/modvb/api/v3/index.json
點更新,然后確定。

下載和安裝 ModVB 語言服務拓展
- 從菜單選擇 擴展→管理擴展
- 在左側選擇 聯機→ModVB
- 下載并安裝 “ModVB Language Services (Built with Roslyn)”
- 重啟 Visual Studio 完成拓展的安裝

如何使用ModVB
注:由于代碼高亮不完全支持這種修改過的 VB,對于未提及運行結果的代碼,使用截圖表示。僅對于代碼高亮沒問題的代碼和帶有執行結果的代碼使用文本表示。
如何:啟用ModVB編譯器
- 新建一個 VB 項目,這里以 .NET 6.0 控制臺應用為例。
- 在項目的引用上右鍵,選擇管理 NuGet 包
- 右上方的下拉框里面,包源選擇 ModVB
- 左邊勾選包含預發布版
- 安裝 “ModVB.Compilers.Toolset”。這個包是 ModVB 編譯器。

如果下載速度慢,請自備對MyGet有效的加速器,或者找已經下載了并且你相信的人分享。
第一批功能:JSON 常量和模式匹配
選擇JSON變量的類型
安裝對應的 NuGet 包
使用 JSON 相關語法之前首先需要選擇 JSON 常量使用哪些庫。目前可選的有 Newtonsoft.Json 和 System.Text.Json。
如果選擇 Newtonsoft.Json,則需要安裝

如果選擇 System.Text.Json,則需要安裝

默認情況下,JSON 常量和模式匹配使用 Newtonsoft.Json 定義的類型。如果選擇它之外的庫,則需要定義編譯常量來更改默認類型。
指定自動推斷的 JSON 類型
假設有個項目,上述兩種庫都安裝了。默認情況下,Json 對象是 Newtonsoft.Json.Linq.JObject。

如果想要默認用 System.Text.Json,需要在項目文件中定義編譯常量。
<PropertyGroup>
<DefineConstants>DEFAULT_JSON_OBJECT_TYPE = "System.Text.Json.Nodes.JsonObject",DEFAULT_JSON_ARRAY_TYPE = "System.Text.Json.Nodes.JsonArray"</DefineConstants>
</PropertyGroup>
效果如下圖所示

按JSON變量的類型構造
那么,如果一個項目里想同時使用兩種JSON類型呢?也是能做到的。只不過你需要寫上JSON變量的類型,而不是讓編譯器自動推斷類型。
![]()
JSON 常量
就像變量可以用 XML 常量初始化一樣,ModVB 支持用 JSON 常量初始化變量,并且用法與 XML 常量有一定的相似性。
此章節的示例使用 Newtonsoft.Json 作為默認 JSON 類型。
以 NuGet 工具版本查詢結果的片段為例。請求 https://dist.nuget.org/tools.json 能夠得到類似于這樣的 JSON并存儲在變量中:

假如你打算生成類似的 JSON,可以把別的變量直接寫進去換掉JSON的值。

有更多的版本需要顯示也是沒問題的,可以用 LINQ 表達式做個 JSON 對象數組出來,然后放到總的 JSON 里面。具體做法可參照下面的示例。
示例
下列代碼展示如何用 LINQ 結合 JSON 常量語法拼一個新的 JSON 出來。
ModVB
Module Program
Sub Main()
Dim latestVersion = "6.3.0"
Dim stableVersions = {
(ver:="6.2.1", uploaded:="2022-06-14T17:00:00.0000000Z"),
(ver:="6.2.0", uploaded:="2022-05-10T13:00:00.0000000Z"),
(ver:="6.1.0", uploaded:="2022-02-15T13:00:00.0000000Z")
}
Dim nugetVersions = {
"nuget.exe": [
{
"version": latestVersion,
"url": $"https://dist.nuget.org/win-x86-commandline/v{latestVersion}/nuget.exe",
"stage": "Released",
"uploaded": "2022-08-09T13:00:00.0000000Z"
},
From verInfo In stableVersions
Select {
"version": verInfo.ver,
"url": $"https://dist.nuget.org/win-x86-commandline/v{verInfo.ver}/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": verInfo.uploaded
}
]
}
Console.WriteLine(nugetVersions)
End Sub
End Module
這段代碼的運行結果是:
JSON
{
"nuget.exe": [
{
"version": "6.3.0",
"url": "https://dist.nuget.org/win-x86-commandline/v6.3.0/nuget.exe",
"stage": "Released",
"uploaded": "2022-08-09T13:00:00.0000000Z"
},
{
"version": "6.2.1",
"url": "https://dist.nuget.org/win-x86-commandline/v6.2.1/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": "2022-06-14T17:00:00.0000000Z"
},
{
"version": "6.2.0",
"url": "https://dist.nuget.org/win-x86-commandline/v6.2.0/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": "2022-05-10T13:00:00.0000000Z"
},
{
"version": "6.1.0",
"url": "https://dist.nuget.org/win-x86-commandline/v6.1.0/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": "2022-02-15T13:00:00.0000000Z"
}
]
}
上面的例子如果你覺得 nugetVersions 的變量聲明太長了,你可以提取變量出來。JSON 常量支持扁平化操作,能夠用來將多個 JSON 對象合并成一個,而不導致對象層次加深。
下面的代碼將第一個版本信息中的兩個屬性提取了變量出來,并且剩余版本信息提取出了另一個變量。程序的執行結果不變。
ModVB
Module Program
Sub Main()
Dim latestVersion = "6.3.0"
Dim stableVersions = {
(ver:="6.2.1", uploaded:="2022-06-14T17:00:00.0000000Z"),
(ver:="6.2.0", uploaded:="2022-05-10T13:00:00.0000000Z"),
(ver:="6.1.0", uploaded:="2022-02-15T13:00:00.0000000Z")
}
Dim stable = From verInfo In stableVersions
Select {
"version": verInfo.ver,
"url": $"https://dist.nuget.org/win-x86-commandline/v{verInfo.ver}/nuget.exe",
"stage": "ReleasedAndBlessed",
"uploaded": verInfo.uploaded
}
Dim releasedStage = {
"stage": "Released",
"uploaded": "2022-08-09T13:00:00.0000000Z"
}
Dim nugetVersions = {
"nuget.exe": [
{
"version": latestVersion,
"url": $"https://dist.nuget.org/win-x86-commandline/v{latestVersion}/nuget.exe",
{releasedStage}
},
stable
]
}
Console.WriteLine(nugetVersions)
End Sub
End Module
JSON 模式匹配
JSON模式匹配能在判斷JSON的結構和內容的同時將所需的信息提取成變量。
例子
以 JSON 常量例子中的 JSON 為例。假設你需要取得所有 stage 是 ReleasedAndBlessed 的 nuget.exe 版本以及其它信息,可以用下面的代碼:
ModVB
Console.WriteLine("所有已發布的穩定版:")
Select Case ShapeOf nugetVersions
Case {"nuget.exe": nodes}
For Each node In nodes
Select Case ShapeOf node
Case {
"version": ver As Version,
"url": url As String,
"stage": "ReleasedAndBlessed",
"uploaded": relaseDate As Date
}
Console.WriteLine($"{ver} 發布于 {relaseDate:F},下載地址是 {url}")
End Select
Next
End Select
代碼產生以下輸出
控制臺
所有已發布的穩定版:
6.2.1 發布于 2022年6月15日 1:00:00,下載地址是 https://dist.nuget.org/win-x86-commandline/v6.2.1/nuget.exe
6.2.0 發布于 2022年5月10日 21:00:00,下載地址是 https://dist.nuget.org/win-x86-commandline/v6.2.0/nuget.exe
6.1.0 發布于 2022年2月15日 21:00:00,下載地址是 https://dist.nuget.org/win-x86-commandline/v6.1.0/nuget.exe
Select Case ShapeOf 語句
Select Case ShapeOf 是模式匹配專用的 Select Case。它會改變Select Case內Case的含義,讓它進行模式匹配,而不會與常規的 Select Case 語法產生沖突。
匹配 JSON 對象
匹配 JSON 對象需要用一對大括號包含 JSON 匹配模式,以下圖為例解釋。

- 匹配的順序是從上到下,在行內從左到右。圖中的屬性1先匹配,屬性2后匹配。
- 想要排除一個屬性,可以匹配一個屬性值是空。圖中要求屬性3必須為空。這樣JSON沒寫屬性3或者屬性3寫了是空才能匹配上。
- 如果冒號左邊寫問號,那么屬性為空的時候仍然會匹配上。圖中的屬性4是可以為空的。包括這個屬性沒寫,或者屬性值寫了是空。
- 如果 JSON 中有別的屬性,并且大括號里面寫了屬性的匹配規則,那么其余的屬性不影響匹配結果。
- 如果大括號里面也可以什么都不寫,這個時候就只能匹配空的 JSON 對象。
匹配 JSON 數組
匹配 JSON 數組需要用一對中括號包含 JSON 匹配模式,以下圖為例解釋。
![]()
- 上圖的意思是,按順序從頭開始匹配數組元素,它至少有指定的這些元素:
"元素1", "元素2", 345, true, false, null。如果數組比預期的長,匹配仍然能夠成功。 - 如果中括號里面什么也不寫,則只能匹配空數組。
匹配 JSON 常量
任何 VB 常量表達式在這里都能使用。包括 Date, Decimal, Nothing。JSON 的常量(true, false, null)也能用。
按類型匹配并定義變量

- 如果值不為空,而且可轉換為指定的類型,則匹配。
- 轉換考慮了
TryCast, VB 內置的轉換規則 以及TryParse之類的其它轉換方式。 - 圖中屬性1會按字符串解析 JSON 內容并且嘗試
TryParse。 - 圖中屬性2會按字符串解析 JSON。
- 圖中屬性3會原樣返回 JSON 的值,前提是屬性3不是空。
用問號表示可選
基本上每個模式匹配表達式最后都可以寫一個問號,讓表達式也能匹配空。這里認為屬性未定義和值為空是相同的情況。下圖是一些例子。
匹配一個可以為空的對象

匹配一個可以為空的值

屬性1可以為空,屬性2匹配一個屬性并定義變量,屬性值可以為空

當屬性值為空時,定義的變量具備它的默認值。
運行時拓展和 API 兼容性
JSON 常量和模式匹配是基于模式的,類似于 LINQ 和 For Each 循環。它并不會綁在特定的庫和類型上。這些功能在分析或編譯代碼時從特定的命名空間查找符合條件的類型,使用其中的成員。你甚至可以只裝包含 ModVB 編譯器的包,具體的模式匹配拓展包由你自己編寫。通過反編譯你的使用 JSON 常量和模式匹配的項目,你可以了解到如何編寫 JSON 常量拓展包和模式匹配拓展包。
參考資料
ModVB 作者寫的兩篇介紹:
- Introducing ModVB—A free, independently-created “mod” for VB.NET that gives you new features just by installing a VSIX
- ModVB “Wave 1”—JSON Literals & Pattern Matching | Anthony's blog (anthonydgreen.net)
版權信息
此文章使用 CC BY-SA 4.0 協議,示例代碼使用 MIT 協議。
此文章目前計劃在 博客園,GitHub,嗶哩嗶哩,百度貼吧 使用用戶名為 Nukepayload2 的賬號發布。如果文章在別的地方出現,或者用戶名不是 Nukepayload2,則屬于被轉載。

浙公網安備 33010602011771號