2015/04/29

VBのループ中のローカル変数

今更という気はしますが、VBで引っ掛かってしまったので、記録として。

VBとC#は兄弟言語ですが、C#から見ると引っ掛かりやすい点があって、ぱっと思いつく限り以下のようなものがあります。
  • Nothingの意味(必ずしもnullではない)
  • 配列のコンストラクタの要素数
  • 整数と実数の自動変換(とくに除算時)
  • オーバーロード解決の優先順
これらとは別に、あまり意識してなかった違いとして、メソッド中のローカル変数の初期値の扱いがあります。C#ではローカル変数を宣言後、値を与えないまま使おうとするとエラーとなってビルドできないのに対し、VBでは値を与えなくてもその型の既定値を使う形でビルドできます。

以下のメソッド中のローカル変数valueについて、LocalVariableCase0では初期値としてFalseを代入しているのに対し、LocalVariableCase1では初期値を代入していませんが、Boolean型の既定値がFalseなので同じ結果になります。
ここまでは問題ありませんが、これをループにすると違いが出ます。

以下のLocalVariableCase2ではループが回る度にvalueはFalseに初期化されますが、LocalVariableCase3ではループしても前回のループで与えられたTrueが残ってしまいます。
ここで試しにLocalVariableCase3のループ中の処理を別メソッドに切り出すと、valueのスコープはそのメソッド中に限定されてLocalVariableCase2と同じ結果になります。
つまり、同一メソッド内のループ中であればループの度にローカル変数を新たに宣言したつもりでも、そうはならず前回の値が維持されます。

これは少しトリッキーというか、予想とは違っていて驚いたわけですが、そういえばVBを勉強し始めたときに変数に初期値を与えておかないと予期しない動作になって危ないと読んだような記憶がありますが、すっかり忘れてました。

というか、何でもかんでも初期値を与えるのもカーゴカルトみたいで無駄だなと思って削っていたら引っ掛かってしまったわけですが、また忘れそうなので書いておきます。

[追記] IL

これだけでは何がどうなっているか明瞭でないので、LocalVariableCase3のILをIL DASMで見ると、こうなっています。


これも今更ですが、ローカル変数はVBでのメソッド中の位置に関わらずILでは冒頭で宣言される形になっています。そこでVBでもローカル変数を冒頭で宣言するように変えたメソッドを作り、そのILを見たのが以下です。


見ての通り、ILは全く同じになります。つまり、ローカル変数の宣言はその位置で変数が初めて確保されることを意味しないので、初期値にリセットするにはきちんと代入しないとダメということですね。

0 コメント :