はじめに
これは、Visual Basic Advent Calendar 2022の23日目の記事となります。
前回、ModVBのインストールの記事を書きました。今回は使い方になります。
使い方
使用するコードは、デフォルトのJSON タイプとしてNewtonsoft.Json
を使用します。
参照
- 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)
JSON定数
変数をXML定数で初期化できるように、ModVBはJSON定数で変数の初期化をサポートしており、その使用法はXML定数と多少似ています。
たとえば、NuGetツールバージョンのクエリ結果のスニペットを見てみましょう。
https://dist.nuget.org/tools.jsonリクエストは、次のようなJSONを取得して変数に格納できます。
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
このコードを実行した結果は次のとおりです。
{
"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オブジェクトを1つにマージするために使用できるフラット化操作をサポートします。
次のコードは最初のバージョン情報から2つの属性を変数に抽出し、残りのバージョン情報から別の変数を抽出します。
プログラムの実行結果は上記と変わりません。
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 を例に取ります。
例えば、stable
がReleasedAndBlessed
であるnuget.exe
のすべてのバージョンとその他の情報を取得する必要があるとします。
次のコードを使用できます。
上記のJSON定数コードの続きに記述してください。
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日 2:00:00, ダウンロード先 https://dist.nuget.org/win-x86-commandline/v6.2.1/nuget.exe
6.2.0 リリース 2022年5月10日 22:00:00, ダウンロード先 https://dist.nuget.org/win-x86-commandline/v6.2.0/nuget.exe
6.1.0 リリース 2022年2月15日 22:00:00, ダウンロード先 https://dist.nuget.org/win-x86-commandline/v6.1.0/nuget.exe
Select Case ShapeOf ステートメント
Select Case ShapeOf
は、Select Case
内のCase
の意味を変え、通常のSelect Case
の構文と矛盾することなくパターンマッチを行うことができる、パターンマッチに特化したSelect Case
です。
JSON オブジェクトに一致
JSONオブジェクトのマッチングには、以下のコードのように、JSONマッチパターンを中括弧で囲む必要があります。
Case {
"属性1": "値1",
"属性2": "値2",
"属性3": null,
"属性4"?: "null可能属性"
- マッチングの順番は列の上から下、左から右の順です。コードでは、属性1が先にマッチングされ、属性2が後にマッチングされる。
- 属性を除外するには、値がNULLの属性にマッチさせることができます。この図では、属性3が空であることを要求しています。このようにJSONは属性3を書かないか、属性3をNULLで書くことで一致させる。
- コロンの左側にクエスチョンマークが書かれている場合、そのプロパティが空でもマッチします。コード中の属性4は空でもよい。これには、属性が書き込まれていない場合や、属性値がNULLで書き込まれている場合も含まれる。
- JSONに別の属性があり、その属性のマッチングルールが中括弧の中に書かれている場合、残りの属性はマッチング結果に影響を及ぼさない。
中括弧の中に何も書かれていない場合は、空のJSONオブジェクトのみがマッチングされます。
JSON配列に一致
JSON配列のマッチングには、下コードのように、JSONマッチパターンを2つの括弧で囲むことが必要です。
Case [ "要素1", "要素2", 345, true, false, null ]
- 上コードの意味は,少なくともこれらの要素が指定された配列の先頭から順に, "要素1", "要素2", 345, true, false, null とマッチすることです. もし配列が予想より長くなっても,マッチは成功します.
- 括弧の中に何も書かれていない場合は、空の配列のみがマッチングされる。
JSON定数に一致
ここでは、VBの定数式であれば何でも使用できます。JSON定数(true, false, null)も使用可能です。
変数の種類によるマッチングと定義
Case {
"属性1": value1 As Version,
"属性2": value1 As String,
"属性3": value3
}
- 値がNULLでなく、指定された型に変換できる場合、マッチする。
- この変換では、
TryCast
、VBの組み込み変換ルール、およびTryParse
などの他の変換方法が考慮されます。 - コードのプロパティ1は、JSONコンテンツを文字列として解析し、
TryParse
を試行します。 - コード中のプロパティ2は、JSONを文字列として解析します。
- コードのプロパティ3は、プロパティ3が空でなければ、JSONの値をそのまま返します。
疑問符を使用してオプションであることを示します
基本的にすべてのパターンマッチング式は、最後にクエスチョンマークを書くことができ、それによって式がNULLにもマッチするようになります。ここでは、属性undefined
と値null
は同じケースと見なします。以下にいくつかの例を示します。
null
になる可能性のあるオブジェクトにマッチする
Case {
"属性1": "値1",
"属性2": "値2"
}?
null 許容値に一致する
Case {
"属性1": "値1",
"属性2": "値2"?
}
属性1は空にすることができ、属性2は属性に一致して変数を定義し、属性値は空にすることができます。
Case {
"属性1": [ "値1" ]?,
"属性2": value1?
}
属性値が空の場合、定義された変数にはデフォルト値があります。
ランタイム拡張機能とAPIの互換性
JSONの定数とパターンマッチは、LINQ
やFor Each
ループと同様、パターンベースです。
特定のライブラリやタイプに縛られることはありません。
これらの関数は、コードの解析やコンパイル時に、特定の名前空間からメンバを使用して適格な型を検索します。
ModVBコンパイラを含むパッケージをインストールするだけで、特定のパターンマッチング拡張を自分で記述することも可能です。
JSON定数やパターンマッチを使用しているプロジェクトをデコンパイルすることで、JSON定数拡張パッケージやパターンマッチ拡張パッケージの書き方を学ぶことができます。
最後に
この記事は下記のModVB紹介記事を参考にDeepLなどを駆使して書きました。
ModVBでは、このように拡張機能で使えるようになります。今回はWave1のみです。
今後のModVBの機能強化に期待しましょう。
ModVBの機能予定
現時点(2022/12/22)では、Wave 1は今年の夏にリリースされました。WAVE 2が12月予定とのことでしたが、まだ未リリースです。
バージョン | 機能内容 |
---|---|
Wave 1 | JSON リテラルとパターン マッチングを中心に展開 |
Wave 2 | XML リテラルの強化 |
Wave 3 | 不明 Wave 2 と Wave 4の中間の機能強化 |
Wave 4 | Async ストーリー強化 |
Wave 5 | LINQ のより深い統合 |