VB.NETではブロックレベルでローカル変数を宣言することができます。 ブロックで宣言されたローカル変数はそのブロック内でのみ有効で、ブロックの外や他のブロックからは参照することができません。 宣言された変数が有効である範囲のことをスコープと呼びます。

ブロック

IfステートメントSelectステートメントFor, For Each, Whileなどの繰り返しのステートメント、Try Catchステートメントなどはローカル変数の有効範囲となるブロックを構成します。

例えば、次のコードで宣言されている二つのローカル変数yはそれぞれのブロック内でのみ有効で、また互いに独立しています。

Sub Main()
  Dim x As Integer ' プロシージャ内のローカル変数

  For x = 1 To 10
    Dim y As Integer ' ブロック内のローカル変数

    y = x - 10
  Next

  ' この部分は宣言されているブロックの外なので変数yは参照できない

  For x = 1 To 10
    Dim y As Single ' ブロック内のローカル変数

    y = CSng(x)
  Next

  ' この部分は宣言されているブロックの外なので変数yは参照できない
End Sub

1つ目と2つ目のForステートメントはそれぞれ別々のブロックを構成します。 そのため、それぞれのブロック内(Forステートメント内)で宣言されているローカル変数yは、独立した別々の変数となります。 異なるプロシージャで同名の変数が宣言されていてもそれぞれのプロシージャでは互いに影響しないのと同様、異なるブロックで同名の変数が宣言されていても互いに影響しません。 また、ブロック内で宣言されている変数yの有効範囲(スコープ)はそのブロック内のみとなるため、ブロック外から変数yを参照することもできません。

一方、プロシージャ内で宣言されているローカル変数xは、ブロック外(Forステートメントの外)で宣言されています。 この変数はプロシージャ内の各ブロックから参照することができます。

Forステートメントだけでなく、Ifなど他のステートメントもブロックを構成します。 IfとElseおよびElseIfはそれぞれ別のブロックとなる点に注意してください。

Sub Main()
  Dim x As Integer = 1 ' プロシージャ内のローカル変数

  If x = 3 Then
    Dim y As Integer = 2 ' Ifブロック内のローカル変数

    Console.WriteLine(y)
  Else
    Dim y As Integer = 3 ' Elseブロック内のローカル変数

    Console.WriteLine(y)
  End If

  ' この部分は宣言されているブロックの外なので変数yは参照できない
End Sub

ブロックは階層構造を持ちます。 そのため、入れ子になったステートメントではブロックも入れ子になります。

Sub Main()
  Dim x As Integer = 1 ' プロシージャ内の変数x

  If x = 3 Then
    Dim y As Integer ' Ifブロック内の変数y

    For y = 2 To 5
      Dim z As Integer = y * 3 ' 入れ子になったブロック内の変数z

      Console.WriteLine(z)
    Next

    ' この部分は宣言されているブロックの外なので変数zは参照できない
  Else
    Dim y As Integer ' Elseブロック内の変数y

    For y = 1 To 3
      Dim z As Integer = y * 2 ' 入れ子になったブロック内の変数z

      Console.WriteLine(z)
    Next

    ' この部分は宣言されているブロックの外なので変数zは参照できない
  End If

  ' この部分は変数yも変数zも参照できない
End Sub

階層構造の上位にあるブロックから下位のブロックで宣言されている変数は参照できませんが、逆に下位にあるブロックから上位のブロックで宣言されている変数を参照することはできます。 プロシージャ内(ブロック外)で宣言されている変数は階層構造の最上位に位置することになります。

Forステートメントではループ変数の宣言も同時に行えるようになっていますが、この変数もForステートメントが構成するブロック内でのみ有効となります。

For x As Integer = 0 To 9
  ' Forステートメント(変数が宣言されているブロック)の内側では変数xを参照できる
  Console.WriteLine(x)
Next

' Forステートメント(変数が宣言されているブロック)の外なので変数xは参照できない

ブロック変数と初期値

値を明示的に初期化しないブロック変数は、プロシージャを抜けるまでその値を保持し続ける点に注意が必要です。

For x As Integer = 1 To 2
  For y As Integer = 1 To 3
    Dim i As Integer ' 初期値を指定せずに宣言したブロック内の変数

    i = i + 1

    Console.WriteLine(i)
  Next
Next
実行結果
1
2
3
4
5
6

この実行結果から分かるとおり、内側のForループを抜けても変数iの値は保持されています。 毎回初期化するようにするには、次のように変数の宣言と同時に初期化する必要があります。

For x As Integer = 1 To 2
  For y As Integer = 1 To 3
    Dim i As Integer = 0 ' 初期値を指定して宣言したブロック内の変数 (ブロックに入るたびに0に初期化される)

    i = i + 1

    Console.WriteLine(i)
  Next
Next
実行結果
1
1
1
1
1
1

初期化と宣言の位置が変われば動作も変わるため、ブロック変数を宣言する箇所には注意する必要があります。

For x As Integer = 1 To 2
  Dim i As Integer = 0 ' 初期値を指定して宣言したブロック内の変数

  For y As Integer = 1 To 3
    i = i + 1

    Console.WriteLine(i)
  Next
Next
実行結果
1
2
3
1
2
3

空のブロック

CやC#では中括弧{ }で囲まれた部分がブロックを構成します。 そのため次のように何らかのステートメントを使わなくても変数の有効範囲を限定するための空ブロックを構成することができます。

C#における空のブロック
int x = 3;

{ // 空のブロック
  int y = 5; // ブロック内の変数
}

// この箇所はブロック外のため変数yを参照できない

VB.NETでブロックを構成するにはなんらかのステートメントを使わなければならないので、このような記述をすることができません。

空のブロックを作成する1つの方法として、常に条件式が真となるIfステートメントを使用する方法があります。

Dim x As Integer = 3

If True Then ' ブロックを構成するためのIfステートメント
  Dim y As Integer = 5 ' ブロック内の変数
End If

このほか、Withステートメントを使用することもできます。

Dim x As Integer = 3

With Nothing ' ブロックを構成するためのWithステートメント
  Dim y As Integer = 5 ' ブロック内の変数
End With

Withステートメントで具体的なオブジェクトを指定する代わりにNothing0True/Falseなどが代用できますが、いずれもWithステートメント内でオブジェクトを参照しなければエラーにはなりません。

ブロックより上位のスコープ

ブロック以外にもスコープを構成する要素には次のようなものが存在します。 また、それぞれの要素はスコープの階層構造の各レベルを構成します。

ブロックより上位のスコープについては、各ページおよびアクセス修飾子を参照してください。