【入門編】実務中級者向け:VB.NETでのReadOnlyとConst、Staticの使い分け:変数のスコープとライフサイクルを制御して堅牢なロジックを作る – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

こんにちは!開発現場で日々、コードの海と格闘している後輩の皆さん。先輩エンジニアの私です。

さて、皆さんはVB.NETでコードを書くとき、変数を宣言する際に `Dim` をとりあえず使っていませんか? あるいは、なんとなく `Const` や `ReadOnly` をつけて満足していませんか?

もし「動けば何でもいいや」でコードを書いているなら、ちょっと立ち止まってみてください。変数の修飾子を正しく選ぶことは、「意図しないバグを防ぐ防壁」を作り、「メモリの無駄遣いをなくす」ための、プログラマーにとって極めて重要なスキルなんです。

ここをクリアすれば、あなたの書くVB.NETコードは一気にプロのそれへとランクアップしますよ。今日は、`Const`、`ReadOnly`、`Static`の3つのキーワードを取り上げ、変数のスコープとライフサイクルを完全に手懐ける極意を伝授します!

1. なぜ「なんとなくDim」ではダメなのか?

実務でシステムを開発していると、最も恐ろしいのは「誰が・どこで・いつ書き換えたか分からない値(副作用)」によるバグです。

例えば、消費税率や消費税計算の基準値など、「絶対に変わってはいけない値」が途中で書き換わってしまったら大惨事ですよね。また、ループの中で毎回無駄にメモリを確保し直すようなコードを書いていると、パフォーマンスの低下を招きます。

これを防ぐのが、今回解説する変数修飾子たちです。それぞれの特徴を図解的なイメージとともに整理してみましょう。

| 修飾子 | いつ決まるか? (決定タイミング) | 書き換えはできるか? | 生存期間 (ライフサイクル) | 主な用途 |
| :— | :— | :— | :— | :— |
| `Const` | コンパイル時(コードを書いた瞬間) | 不可(定数) | プログラム実行中ずっと | 消費税率、固定パス、マジックナンバーの排除 |
| `ReadOnly` | 実行時(インスタンス生成時など) | 不可(読み取り専用) | オブジェクトの生存期間中 | 設定値、依存するオブジェクトの保持 |
| `Static` | 実行時(初回通過時) | (通常の変数と同じ) | プログラム終了まで保持される | カウンター、キャッシュ、状態保持 |

それでは、一つずつ現場での実践的な使い方を見ていきましょう!

2. `Const` ―― 「絶対に変わらない絶対不変の真理」

`Const`(コンスタント)は、その名の通り定数を定義します。コードをコンパイルする時点で値が確定していなければならず、後から書き換えることは絶対にできません。

悪い例:マジックナンバーの蔓延

‘ 【アンチパターン】どこからともなく出てくる「3」や「1.10」
If userType = 3 Then
totalPrice = basePrice 1.10
End If

この「3」や「1.10」は何を意味するのでしょうか? 3ヶ月後、あなた自身が見ても絶対に忘れています。そして税率が「1.10」から変わったとき、コード全体の「1.10」を探して書き換えるハメになります(ヒューマンエラーの温床です)。

良い例:`Const` による定数化

Public Class TaxCalculator
‘ 消費税率は絶対に変わらないので Const で定義する
‘ パスカルケース(先頭大文字など)で命名するのが.NETの作法です
Private Const StandardTaxRate As Decimal = 0.1D
Private Const UserTypeAdmin As Integer = 3

Public Sub Calculate(userType As Integer, basePrice As Decimal)
If userType = UserTypeAdmin Then
Dim totalPrice As Decimal = basePrice (1.0D + StandardTaxRate)
Console.WriteLine($”合計金額: {totalPrice}”)
End If
End Sub
End Class

ここがポイント:
`Const` を使うことで、コードの意図が明確になり、メンテナンス性が劇的に向上します。また、コンパイル時に値がコードに埋め込まれるため、パフォーマンス面でも非常に有利です。

3. `ReadOnly` ―― 「生まれてから死ぬまで変わらない、だけど動的に決まる」

「定数にしたいけれど、値が決まるのはプログラムが動いてから(ファイルから読み込む、DBから取得するなど)なんだよな…」という時に使うのが `ReadOnly` です。

`Const` はコンパイル時に値が決まっている必要がありましたが、`ReadOnly` はコンストラクタ(初期化処理)の中で一度だけ値を入れることができます。

実装例:設定ファイルを保持するクラス

Public Class ApplicationSettings
‘ 読み取り専用フィールドとして宣言
Public ReadOnly Property ConnectionString As String

‘ コンストラクタで外部から値を受け取り、一度だけ初期化する
Public Sub New(connString As String)
‘ ここで代入できるのは「最初の一回」だけ!
Me.ConnectionString = connString
End Sub

Public Sub ShowSettings()
‘ Me.ConnectionString = “hoge” ‘ ← エラー!ReadOnlyなので書き換えようとすると怒られます
Console.WriteLine($”現在の接続先: {ConnectionString}”)
End Sub
End Class

ここがポイント:
オブジェクト指向の現場では、インスタンスの状態が途中で勝手に変わらないこと(イミュータブル=不変性)が、バグの少ない堅牢なシステムを作るための大原則です。「初期化したら二度と書き換えない」プロパティには、迷わず `ReadOnly` を付与しましょう。

4. `Static` ―― 「メソッドが終わっても、君のことは忘れない」

さて、ここからが中級者へのステップアップの肝です。`Const` や `ReadOnly` が「書き換えられたくない値」だったのに対し、`Static`「値を保持し続けたい変数」に使います。

通常、SubやFunctionなどのプロシージャ(メソッド)内で宣言された `Dim` 変数は、そのメソッドの実行が終わるとメモリから消え去り、次に呼ばれたときはリセットされます。
しかし、`Static` をつけると、メソッドが終了しても値が保持され、次にそのメソッドが呼ばれたときにも前回の値を引き継ぎます。

実装例:メソッドの呼び出し回数をカウントする

Public Class Logger

Public Sub RecordProcess(processName As String)
‘ Static を使うことで、この変数はメソッドが終了しても消滅しない
Static callCount As Integer = 0

callCount += 1

Console.WriteLine($”[{ProcessName}] が実行されました。通算実行回数: {callCount} 回目”)
End Sub

End Class

‘ — 呼び出し側のイメージ —
‘ Dim logger As New Logger()
‘ logger.RecordProcess(“データ保存”) ‘ → 通算実行回数: 1 回目
‘ logger.RecordProcess(“データ保存”) ‘ → 通算実行回数: 2 回目(カウントが引き継がれている!)

注意すべきダークサイド:スレッドセーフティとライフサイクル

`Static` は非常に便利ですが、「クラスのインスタンスが異なっても、メソッド単位(あるいは変数スコープ単位)で値が共有される」という特性があります。
特にマルチスレッド環境や、ASP.NET、複数画面からの並行処理があるデスクトップアプリなどで安易に `Static` を使うと、「予期せぬタイミングで値が書き換わっている(競合状態)」という、原因究明が極めて困難なバグを生む魔物に変貌します。

基本的には、フォームアプリケーションでコントロールの状態を少し覚える場合や、厳密にシングルスレッドで動作する処理のカウンターなどに限定して使うのが賢明です。ビジネスロジックのコア部分で状態を保持したいなら、`Static` ではなく、クラスのフィールド(メンバ変数)としてライフサイクルを明示的に管理すべきです。

まとめ:適材適所の修飾子選びで、ワンランク上のプログラマーへ

いかがでしたでしょうか? 今回のまとめです。

1. `Const`

  • 値が完全に固定。コンパイル時に決まる。
  • 例: 消費税率、数学的定数、固定の制限値。

2. `ReadOnly`

  • 値は実行時に決まるが、一度初期化したら二度と書き換えさせない。
  • 例: 外部から注入される設定値、イミュータブルなオブジェクトのプロパティ。

3. `Static`

  • メソッドが終了しても値の記憶を保持し続ける。
  • 例: 簡易的なカウンターや状態保持(※マルチスレッドでの扱いに注意!)。

「なんとなく `Dim`」を卒業し、変数の寿命と書き換え可能性をあなたが完全にコントロールできるようになれば、あなたのコードは驚くほど堅牢になり、バグの温床を断つことができます。

ここをクリアすれば、Visual Basic (VB / VB.NET)の基本、そしてオブジェクト指向の設計思想の片鱗はもうバッチリですよ!
日々のコーディングにぜひ取り入れてみてください。それでは、次の開発現場でお会いしましょう!

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