【入門編】初心者向け:VB.NETの配列とList(Of T)の明確な使い分け:固定長と可動長のメモリ構造から学ぶコレクション選択の鉄則 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

【VB.NET基礎】配列 vs List(Of T)の明確な使い分け!メモリ構造から学ぶコレクション選択の鉄則

こんにちは!VBAでの業務自動化から一歩を踏み出し、VB.NETによる本格的なシステム開発の世界へようこそ。

プログラミングの規模が大きくなり、処理するデータ量が増えてくると、必ずぶつかる大きな壁があります。それが「複数のデータをどの容器(データ構造)に入れて扱うか?」という問題です。

VB.NETには、昔ながらの「配列(Array)」と、現代的な.NETの標準である「`List(Of T)`」という代表的な2つの容器が存在します。

「動かすだけならどっちでもいいんじゃないの?」と思われるかもしれません。しかし、ここを正しく理解して使い分けられるようになると、プログラムの動作速度が飛躍的に向上し、メモリの無駄遣いや予期せぬエラー(バグ)を劇的に減らすことができるようになります。

今回は、優しく、しかし技術の本質(メモリの仕組み)に踏み込んで、配列と`List(Of T)`の明確な使い分けの鉄則を伝授します。ここをクリアすれば、Visual Basic (VB / VB.NET)の基本はバッチリですよ!

1. イメージで掴む!配列とList(Of T)の根本的な違い

まずは、難しいコードを見る前に、コンピュータのメモリの中で何が起きているかを視覚的にイメージしてみましょう。

【配列 (Array)】= 最初に席数をガチガチに固定予約する「映画館の指定席」
┌───┬───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ <- 途中で席を増やしたり減らしたりできない! └───┴───┴───┴───┴───┘ 【List(Of T)】= 人数に合わせて自動で拡張してくれる「伸縮自在なパーティ会場」 ┌───┬───┬───┐ + Add("データ") ──> ┌───┬───┬───┬───┐
│ 0 │ 1 │ 2 │ │ 0 │ 1 │ 2 │ 3 │ (内部で自動調整)
└───┴───┴───┘ └───┴───┴───┴───┘

  • 配列(固定長)

プログラム実行時に「要素数(サイズ)」を決定したら、後から変更できません。メモリ上に「連続した固定の領域」を一括して確保するため、非常に軽量でアクセスが高速です。

  • `List(Of T)`(可動長/動的配列)

要素の追加(`Add`)や削除(`Remove`)が自由自在に行えます。裏側では.NET Framework/.NET Coreがメモリ管理を高度に自動処理してくれている賢い仕組みです。

2. 配列(Array)の深層:なぜ「途中変更」が得意ではないのか?

VB.NETでの配列の宣言と使い方を見てみましょう。

基本的な配列のコード例

Module Module1
Sub Main()
‘ 要素数5個の文字列配列を宣言 (インデックスは0から4まで)
Dim fixedArray(4) As String

‘ 値の代入
fixedArray(0) = “月曜日”
fixedArray(1) = “火曜日”
‘ … 中略 …
fixedArray(4) = “金曜日”

‘ ループ処理(配列は要素数が固定のため、高速に走査できます)
For i As Integer = 0 To fixedArray.Length – 1
Console.WriteLine($”Index {i}: {fixedArray(i)}”)
Next
End Sub
End Module

【超重要】VBA出身者が陥る「ReDim Preserve」の罠

VBAに慣れている方は、「配列でも `ReDim Preserve` を使えばサイズを変更できるじゃないか」と思うかもしれません。

‘ 【非推奨】VB.NETでこれを多用してはいけません!
ReDim Preserve fixedArray(5)

実はこれ、見た目上は配列が伸びているように見えますが、裏側(メモリ領域)では「新しいサイズの配列を別場所に丸ごと作り直し、古い配列の値を1つずつコピペして、古い配列を破棄する」という非常に負荷の高い処理を行っています。

何千回、何万回とループ内で `ReDim Preserve` を呼び出すと、CPUとメモリ(ガベージコレクション)に破壊的な負担がかかり、アプリが極端に重くなります。配列はあくまで「サイズが決まっているとき」に使うのが鉄則です。

3. `List(Of T)` の深層:なぜ自由自在に伸び縮みできるのか?

次に、現代のVB.NET開発で主役となる `List(Of T)`(リスト・オブ・ティー)を見てみましょう。この `(Of T)` は「ジェネリクス」と呼ばれる仕組みで、「何の型のリストか」を宣言時に指定します。

基本的な `List(Of T)` のコード例

Imports System.Collections.Generic

Module Module1
Sub Main()
‘ String型の要素を扱う動的リストを生成
‘ (Of String) と指定することで、文字列以外が入るのを防ぐ(型安全性)
Dim dynamicList As New List(Of String)()

‘ 要素の追加 (後からいくらでも追加可能)
dynamicList.Add(“リンゴ”)
dynamicList.Add(“バナナ”)
dynamicList.Add(“ミカン”)

‘ 要素の削除も簡単
dynamicList.Remove(“バナナ”)

‘ For Each ループで快適に取得
For Each fruit As String In dynamicList
Console.WriteLine($”果物: {fruit}”)
Next

‘ LINQを使った便利な検索(条件に合うものを一発で抽出)
Dim result As String = dynamicList.Find(Function(f) f.StartsWith(“ミ”))
Console.WriteLine($”「ミ」から始まる果物: {result}”)
End Sub
End Module

`List(Of T)` の内部メモリの秘密(CapacityとCount)

`List(Of T)` は魔法で伸び縮みしているわけではありません。実は内部に「隠された配列」を持っています。

  • `Count`:現在実際に入っている要素の数
  • `Capacity`:内部の「隠し配列」が現在確保している最大の部屋数

`List(Of T)` に `Add` していき、内部の部屋数(Capacity)がいっぱいになると、`List(Of T)` は自動的に現在の2倍の広さの隠し配列を再確保して、スムーズにデータを拡張します。開発者が `ReDim Preserve` のような泥臭いメモリ管理をしなくて済むよう、内部で完璧に最適化されているのです。

4. プロが教える「コレクション選択の鉄則」

それでは、実際の現場で「配列」と「`List(Of T)`」のどちらを選ぶべきか、迷わなくなる基準を整理しましょう。

判定チャート

【データ構造の選択フロー】

データの個数は、プログラム実行前から完全に決まっていますか?

├── [YES] ──> 【配列 (Array)】を使用
│ 例:曜日(7個)、12ヶ月(12個)、RGB色成分(3個)、
│ 固定長のバイナリデータ処理、パフォーマンスが極限まで求められる処理

└── [NO] ──> 【List(Of T)】を使用
例:データベースから取得した件数不明のレコード、
ユーザーが画面で入力した可変データ、
途中で検索・削除・並び替えを行いたいデータ

比較まとめ表

| 項目 | 配列 (Array) | List(Of T) |
| :— | :— | :— |
| サイズ(要素数) | 固定(作成時に決定) | 動的(自由に追加・削除が可能) |
| メモリオーバーヘッド | 最小(非常に軽量) | わずかに存在する(制御用オブジェクト分) |
| データアクセス速度 | 最速 | 非常に高速(配列とほぼ遜色なし) |
| 要素の追加・削除 | 不可(`ReDim`は高コスト) | メソッド一発で可能(`Add`, `Remove`等) |
| 機能性(便利メソッド) | 基本的な機能のみ | 豊富(検索、ソート、LINQとの親和性が抜群) |
| 推奨される用途 | 要素数が不変のデータ、低レイヤ処理 | 通常の業務アプリケーション全般(基本はこちら) |

5. 実践コード:ファイル読み込み処理で見る適切な使い分け

最後に、実際の業務開発でよくある「CSVファイルやテキストファイルを読み込む処理」を例に、両者の素晴らしい連携例を紹介します。

Imports System.IO
Imports System.Collections.Generic

Module Module1
Sub Main()
Dim filePath As String = “C:\temp\sample_data.txt”

‘ 【シナリオ】
‘ 行数がわからない外部ファイルを読み込む場合、
‘ 最初に List(Of T) で受けるのが鉄則です!

Dim linesList As New List(Of String)()

If File.Exists(filePath) Then
‘ ファイルを1行ずつ読み込んでListに追加(可動長が威力を発揮)
Using reader As New StreamReader(filePath)
While Not reader.EndOfStream
Dim line As String = reader.ReadLine()
‘ 空行でなければリストに追加
If Not String.IsNullOrWhiteSpace(line) Then
linesList.Add(line)
End If
End While
End Using

Console.WriteLine($”読み込み完了: {linesList.Count} 件のデータを取得しました。”)

‘ — もし他APIや古いライブラリ等で「配列」を求められた場合 —
‘ List(Of T) から 配列 への変換は ToArray() メソッド一発で完了します!
Dim linesArray As String() = linesList.ToArray()

Console.WriteLine($”配列に変換されました。要素数: {linesArray.Length}”)
Else
Console.WriteLine(“ファイルが存在しません。”)
End If
End Sub
End Module

このコードの美しさのポイント

1. 読み込み時:何行あるかわからないため、柔軟に拡張できる `List(Of String)` を使用しています。`ReDim Preserve` を使う必要は一切ありません。
2. 後処理:もし「配列形式でデータを渡さなければならない外部システム」があっても、`ToArray()` メソッドを使えば、メモリ効率を最大化させた状態の配列を一瞬で作ることができます。

まとめ:モダンなVB.NETプログラミングへの第一歩

今回の重要ポイントを振り返りましょう。

1. 要素数が不変なら「配列」。軽量で最高速。
2. 要素数が変わる、または不明なら「`List(Of T)`」。現代のVB.NET開発の標準。
3. 配列に対して `ReDim Preserve` を連発するのはNG! メモリと性能に悪影響を与えます。動的に扱うなら迷わず `List(Of T)` を選びましょう。

データ構造の選択に根拠を持てるようになると、あなたの書くVB.NETコードは「ただ動くコード」から「美しく、速く、壊れにくいコード」へと劇的に進化します。

ここをクリアすれば、Visual Basic (VB / VB.NET)の基本はバッチリですよ!自信を持って、次のステップ(LINQやオブジェクト指向)へ進んでいきましょう。応援しています!

タイトルとURLをコピーしました