VB.NETでもReDimで配列の大きさを変更したい

はじめに

適当に『UnicodeUnix Codeの略でUnixで使われている文字コード体系なんですよ〜』なんてホラ吹いていたら本気にされました。 多分バレたら殺されます。

さて今回は使いどころが正直思いつかないReDimステートメントのお話です。

ReDim ステートメント (Visual Basic)

なかなかに翻訳がアレですが、軽く確認した感じ

  • 使えるのはプロシージャ(メソッド)内だけ
  • 配列のサイズを変えられる
  • 1次元ではなく多次元の配列でもつかえる
  • ただし内容を保持したままサイズを変更できるのは最終次元のみ
  • 配列の次元は変えられない

という事らしいです。 つまり3次元から2次元へ次元をシフトして画面内のあの子に愛の告白などはサポートされていないとのことです。残念

正直多次元配列はあんまり使わないので、1次元配列について軽く見てみようかなと思います。

Let's IL

とりあえずのサンプルコードがこちら

Dim array = New Integer() {1, 2, 3, 4, 5}

ReDim Preserve array(10)

For Each it In array
    Console.Write("{0} ", it)
Next
Console.WriteLine()

ReDim Preserve array(3)

For Each it In array
    Console.Write("{0} ", it)
Next
Console.WriteLine()

それでもって実行結果がこちら

1 2 3 4 5 0 0 0 0 0 0
1 2 3 4

VBでは指定した数+1が配列の要素数になるとか、拡張された領域はデフォルト値で初期化されるとか割とどうでもいい。 私の興味はどのようなILが生成されているのかという事です。

ループのコードが割と邪魔なので、最小の要素のコードで逆アセンブリしてILを見てみます。

Dim array = New Integer() {1, 2, 3, 4, 5}
ReDim Preserve array(10)
ReDim Preserve array(3)

んで、生成されたILがこちら

  .maxstack  3
  .locals init ([0] int32[] 'array',
           [1] int32[] VB$t_array$S0)
  IL_0000:  nop
  IL_0001:  ldc.i4.5
  IL_0002:  newarr     [mscorlib]System.Int32
  IL_0007:  stloc.1
  IL_0008:  ldloc.1
  IL_0009:  ldc.i4.0
  IL_000a:  ldc.i4.1
  IL_000b:  stelem.i4
  IL_000c:  ldloc.1
  IL_000d:  ldc.i4.1
  IL_000e:  ldc.i4.2
  IL_000f:  stelem.i4
  IL_0010:  ldloc.1
  IL_0011:  ldc.i4.2
  IL_0012:  ldc.i4.3
  IL_0013:  stelem.i4
  IL_0014:  ldloc.1
  IL_0015:  ldc.i4.3
  IL_0016:  ldc.i4.4
  IL_0017:  stelem.i4
  IL_0018:  ldloc.1
  IL_0019:  ldc.i4.4
  IL_001a:  ldc.i4.5
  IL_001b:  stelem.i4
  IL_001c:  ldloc.1
  IL_001d:  stloc.0
  IL_001e:  ldloc.0
  IL_001f:  castclass  [mscorlib]System.Array
  IL_0024:  ldc.i4.s   11
  IL_0026:  newarr     [mscorlib]System.Int32
  IL_002b:  call       class [mscorlib]System.Array [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Utils::CopyArray(class [mscorlib]System.Array,
                                                                                                                                   class [mscorlib]System.Array)
  IL_0030:  castclass  int32[]
  IL_0035:  stloc.0
  IL_0036:  ldloc.0
  IL_0037:  castclass  [mscorlib]System.Array
  IL_003c:  ldc.i4.4
  IL_003d:  newarr     [mscorlib]System.Int32
  IL_0042:  call       class [mscorlib]System.Array [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Utils::CopyArray(class [mscorlib]System.Array,
                                                                                                                                   class [mscorlib]System.Array)
  IL_0047:  castclass  int32[]
  IL_004c:  stloc.0
  IL_004d:  nop
  IL_004e:  ret

なんてことのない、VBが内部で新しく配列を作り直してコピーしてるだけでした*1。 『まぁ、そうなるな』以外の感想が出てこない結果ですね。

でもまぁ、一発で配列のサイズを変更できたら使い所によってはかなり便利かもしれませんね。

ちなみに同じ配列ネタとして、レガシーVBでは配列のインデックス範囲を自由に設定できたそうですが、VB.NETではそれは廃止されたそうですね。

( ^o^)ReDimステートメントで自由に配列のサイズを変更できるぞ
( ˘⊖˘) 。o(待てよ?List等のコレクションを使えばそもそもサイズとかそこまで気にしなくてもいいはずでは?)
|コーディングガイドライン|┗(☋` )┓三
( ◠‿◠ )☛そこに気づいたか・・・消えてもらう
▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂うわああああああ

*1:この事はリンク先のmsdnに普通に書いてあるんですけどね。