はじめに
これは、Visual Basic Advent Calendar 2025の20日目の記事となります。
400以上のいいねが付いた C# の記事が上がりました。
Visual Basic では、どうなるだろうと思って書いてみます。
C# の元記事を Visual Basic に単純に言語変換できるところは元記事を見ていただき、サポートしていない部分などをチェックしていきます。
処理別リスト
WinForms は除外します。
| No. | カテゴリ | パターン | C# (導入) | VB.NET 対応状況 |
|---|---|---|---|---|
| 1 | 非同期処理 | Begin/End/BackgroundWorker → async/await | C# 5.0 / .NET 4.5 | VB 2012 |
| 2 | 非同期処理 | HttpWebRequest/WebClient → HttpClient | C# 5.0 / .NET 4.5 | VB 2012 |
| 3 | コレクション | ArrayList/Hashtable → ジェネリックコレクション | C# 2.0 / .NET 2.0 | VB 2005 |
| 4 | リソース管理 | try/finally で Dispose → using/await using | using (C# 2.0),await using (C# 8.0) | using (VB 2005),await using (❌ 非対応) |
| 5 | LINQ | 手続きループ処理 → LINQ(適材適所) | LINQ (C# 3.0 / .NET 3.5) | VB 2008 |
| 6 | 文字列処理 | String.Format/連結 → 文字列補間($"") | C# 6.0 / .NET 4.6 | VB 2015 |
| 7 | パターン | is + キャスト → パターンマッチング | C# 7.0 |
TypeOf…Isなどで可能だが ❌C# のような構文は非対応 |
| 8 | 制御フロー | switch 文 → switch 式 | C# 8.0 / .NET Core 3.0 | ❌switch 式は非対応 |
| 9 | DTO | DTO クラス冗長 → record/with | C# 9.0 / .NET 5 | ❌ 非対応 |
| 10 | 日時処理 | DateTime.Now 乱用 → DateTimeOffset.UtcNow | .NET 2.0 | ライブラリ側対応 |
| 11 | シリアライザ | BinaryFormatter/旧シリアライザ → System.Text.Json | .NET Core 3.0 / .NET 5 | ライブラリ側対応 |
| 12 | スレッド管理 | Thread 直使用 → Task/ThreadPool | C# 4.0 / .NET 4.0 | VB2010 |
| 13 | タイマー | Timer 多用 → PeriodicTimer (.NET 6+) | .NET 6 | ライブラリ側対応 |
| 14 | データ層 | ADO.NET 同期 API → 非同期/軽量 ORM | C# 5.0 / .NET 4.5 | VB2012 |
| 15 | 乱数生成 | Random の単純使用 → RandomNumberGenerator | .NET 5以降に推奨パターンとして定着 | C# 同様 |
| 16 | 例外処理 | 例外の後処理 → 例外フィルタ catch when | C# 6.0 / .NET 4.6 | VB2015 |
| 17 | Null チェック | if (obj != null) だらけ → ?. / ??= / Nullable | ?. (C# 6.0), ??=, Null許容参照型 (C# 8.0) | ?. (VB2015),??=(❌ 非対応) |
| 18 | プロパティ | 手書きプロパティ → 自動実装/式本体メンバー | 自動実装 (C# 3.0), 式本体 (C# 6.0) | 自動実装(VB2008),式本体(VB2015) |
| 19 | インスタンス化 | new Type() 明示 → 目標型 new | ターゲット型の new() (C# 9.0 / .NET 5) | ❌ 非対応 |
| 20 | データコピー | 手動コピー → with/分解(ValueTuple) | C# 7.0 / .NET 4.7 | VB2017 |
| 21 | 設定管理 | app.config/Web.config → appsettings.json + Options | .NET Core 1.0 / .NET 5 | ライブラリ側対応 |
| 22 | ログ出力 | Trace.WriteLine → ILogger | .NET Core 1.0 / .NET 5 | ライブラリ側対応 |
コレクション・データ型関連
4) try/finally で Dispose → using/await using
async の場合は await using
await using var fs = new FileStream(
path, FileMode.Open, FileAccess.Read,
FileShare.Read, bufferSize: 4096, options: FileOptions.Asynchronous);
// .NET 6+ 推奨:Memory<byte> + CancellationToken
var buffer = new byte[1024];
int read = await fs.ReadAsync(buffer.AsMemory(), CancellationToken.None);
// または古いオーバーロード(.NET Framework との互換性が必要な場合)
int read2 = await fs.ReadAsync(buffer, 0, 1024);
VB.NET にはAwait Usingが存在しない
そのため、非同期解放が必要な場合はFinallyでAwait DisposeAsync()を明示的に呼ぶ
Dim fs As FileStream = Nothing
Try
fs = New FileStream(
path, FileMode.Open, FileAccess.Read, FileShare.Read,bufferSize:=4096, options:=FileOptions.Asynchronous)
' .NET 6+ 推奨:Memory(Of Byte) + CancellationToken
Dim buffer(1023) As Byte
Dim read As Integer = Await fs.ReadAsync(buffer.AsMemory(), CancellationToken.None)
' または古いオーバーロード(.NET Framework 互換)
Dim read2 As Integer = Await fs.ReadAsync(buffer, 0, 1024)
Finally
' await using が使えないため、明示的に非同期解放
If fs IsNot Nothing Then
Await fs.DisposeAsync()
End If
End Try
LINQ・言語機能関連
7) is + キャスト → パターンマッチング
if (obj is Customer c)
{
Console.WriteLine(c.Name);
}
補足: VB.NET もパターンマッチング(TypeOf ... Is ...)は可能ですが、C# のようにis Customer cで同時に変数宣言する構文はありません。
If TypeOf obj Is Customer Then
Dim c = CType(obj, Customer)
Console.WriteLine(c.Name)
End If
8) switch 文 → switch 式
string msg = status switch
{
0 => "OK",
1 => "Warn",
_ => "NG"
};
VB.NET は値を返す式としてのswitchはサポートされていません。
Select Caseは、break文が不要
Dim msg As String
Select Case status
Case 0
msg = "OK"
Case 1
msg = "Warn"
Case Else
msg = "NG"
End Select
このくらいなら、三項演算子で代用
Dim msg = If(status = 0, "OK", If(status = 1, "Warn", "NG")
DTO・オブジェクト関連
DTO クラス冗長 → record/with
public record User(string Name, int Age);
// 用途(同じ)
var user = new User("Alice", 30);
// with で不変コピー
var user2 = user with { Age = 31 };
VB.NET には C# のrecord型の等価機能がありません。
代替としては、ClassまたはStructureを使用し、必要な等価性・コピー機能を自前で実装します。
もしくは、VB-Record-Source-Generator を使う。
with式に対応していません
Null チェック・参照関連
17) if (obj != null) だらけ → ?. / ??= / Nullable Reference Types
name = user?.Name; // user が null なら null を返す
config ??= DefaultConfig(); // null 時だけ代入
VB.NET にはC# の??や??=はありません。
三項演算子で書けるが、完全には同等ではない
name = user?.Name ' user が Nothing なら Nothing を返す
' 三項演算子+一時変数でほぼ同等
Dim tmp = config
config = If(tmp = Nothing, DefaultConfig() : tmp)
C# 8.0 以降で??=が追加された理由は
- 三項演算子では 安全・簡潔に書けない(ローカル変数限定 なら可)
- 特にプロパティやフィールドで問題が起きやすい
インスタンス作成関連
19) new Type() 明示 → 目標型 new
List<string> list = new();
Dictionary<int, string> dict = new();
VB.NET ではC# のtarget-typed new省略は非対応
Dim list As New List(Of String)
Dim dict As New Dictionary(Of Integer, String)()
オブジェクトコピー関連
20) 手動コピー → with/分解(ValueTuple)
ValueTuple で分解
var (min, max) = GetRange();
VB.NET では、タプルを複数の変数に“アンパック”する方法はない
変数ごとに1行が必要になる。
Dim r = GetRange()
Dim min = r.min
Dim max = r.max
VB.NET は with式に対応していません
最後に
VB.NETは、言語の進化(新機能の追加)を停止しました。Visual Basic 2017 が最後の新機能の追加となっています。
例として ??=やrecored型、パターンマッチング、直近だとfieldキーワード が対応していません。
ただし、ライブラリ側の新機能は、VB.NET でも対応しています。