VB.NETの関数で参照型データ(オブジェクト型)を引数にする場合、値渡しと参照渡しで少し挙動が異なります。
先ず以下のソースを見て下さい。2個の ArrayList 変数を生成し、それぞれ値渡しと参照渡しの値設定関数をコールしています。 「SetArrList1」と「SetArrList2」がコールされる関数ですが、この二つの関数は内部の処理は全く同じ様な処理で 引数の宣言が「ByVal」か「ByRef」かの違いだけです。
「SetArrList1」と「SetArrList2」共に、ArrayListにデータを5個追加する処理をしていますが、 値渡しでも、参照渡しでも渡された引数のArrayListの中のデータが変わることがわかると思います。
「SetArrList1」と「SetArrList2」実行後のデータ表示でそれが分かります。
- ' 値渡し・参照渡しのテスト
- Public Shared Sub Main()
- 'ArrayListその1生成
- Dim Lst1 As New ArrayList
- 'ArrayListその2生成
- Dim Lst2 As New ArrayList
- '値渡し:参照型データ(引数)への値追加
- Call SetArrList1(Lst1)
- '参照渡し:参照型データ(引数)への値追加
- Call SetArrList2(Lst2)
- Console.WriteLine("*** ArrayListその1全て表示")
- For i As Integer = 0 To Lst1.Count - 1
- Console.WriteLine(String.Format("Lst1(" & i & ") = {0}", Lst1(i)))
- Next
- Console.WriteLine("*** ArrayListその2全て表示")
- For i As Integer = 0 To Lst2.Count - 1
- Console.WriteLine(String.Format("Lst2(" & i & ") = {0}", Lst2(i)))
- Next
- End Sub
- ' 値渡し・参照型データ(引数)への値追加
- Private Shared Sub SetArrList1(ByVal List As ArrayList)
- 'ArrayListに要素追加(1 ~ 5)
- For i As Integer = 1 To 5
- List.Add(i)
- Next
- End Sub
- ' 参照渡し・参照型データ(引数)への値追加
- Private Shared Sub SetArrList2(ByRef List As ArrayList)
- 'ArrayListに要素追加(11 ~ 15)
- For i As Integer = 11 To 15
- List.Add(i)
- Next
- End Sub
このソースの実行結果を見てみます。
結果からみて注意することは、参照型データを引数で渡す時には値渡しであっても、 その参照型のメソッドを使って参照型の中のデータは変更できるということです。
そこで、次に渡された引数に対して変更を行った場合にはどうなるのかを見てみます。
先ほどのソースに「SetArrList1New」「SetArrList2New」の関数を追加します。 それぞれは内部で、新規にArrayListを生成し、1件のデータを追加後、引数の変数に設定しています。 引数の宣言が「ByVal」か「ByRef」の違いがあるだけです。
- ' 値渡し・参照渡しのテスト
- Public Shared Sub Main()
- 'ArrayListその1生成
- Dim Lst1 As New ArrayList
- 'ArrayListその2生成
- Dim Lst2 As New ArrayList
- '値渡し:参照型データ(引数)への値追加
- Call SetArrList1(Lst1)
- '参照渡し:参照型データ(引数)への値追加
- Call SetArrList2(Lst2)
- Console.WriteLine("*** ArrayListその1全て表示")
- For i As Integer = 0 To Lst1.Count - 1
- Console.WriteLine(String.Format("Lst1(" & i & ") = {0}", Lst1(i)))
- Next
- Console.WriteLine("*** ArrayListその2全て表示")
- For i As Integer = 0 To Lst2.Count - 1
- Console.WriteLine(String.Format("Lst2(" & i & ") = {0}", Lst2(i)))
- Next
- Console.WriteLine("****************************")
- '値渡し:参照型データ(引数)への新規オブジェクト設定
- Call SetArrList1New(Lst1)
- '参照渡し:参照型データ(引数)への新規オブジェクト設定
- Call SetArrList2New(Lst2)
- Console.WriteLine("*** ArrayListその1全て表示")
- For i As Integer = 0 To Lst1.Count - 1
- Console.WriteLine(String.Format("Lst1(" & i & ") = {0}", Lst1(i)))
- Next
- Console.WriteLine("*** ArrayListその2全て表示")
- For i As Integer = 0 To Lst2.Count - 1
- Console.WriteLine(String.Format("Lst2(" & i & ") = {0}", Lst2(i)))
- Next
- End Sub
- ' 値渡し・参照型データ(引数)への値追加
- Private Shared Sub SetArrList1(ByVal List As ArrayList)
- 'ArrayListに要素追加(1 ~ 5)
- For i As Integer = 1 To 5
- List.Add(i)
- Next
- End Sub
- ' 参照渡し・参照型データ(引数)への値追加
- Private Shared Sub SetArrList2(ByRef List As ArrayList)
- 'ArrayListに要素追加(11 ~ 15)
- For i As Integer = 11 To 15
- List.Add(i)
- Next
- End Sub
- ' 値渡し・関数内でオブジェクトを新規作成し引数に設定
- Private Shared Sub SetArrList1New(ByVal List As ArrayList)
- Dim ListNew As New ArrayList 'ArrayListの新規生成
- ListNew.Add(1000) '1000を値として追加
- List = ListNew '引数に設定
- End Sub
- ' 参照渡し・関数内でオブジェクトを新規作成し引数に設定
- Private Shared Sub SetArrList2New(ByRef List As ArrayList)
- Dim ListNew As New ArrayList 'ArrayListの新規生成
- ListNew.Add(2000) '2000を値として追加
- List = ListNew '引数に設定
- End Sub
結果から分かることは、「ByVal」の引数ではコール元のArrayListの変数「Lst1」は変化しないことです。 また、「ByRef」の引数の方は、「Lst2」の中身が変わってしまっています。 「Lst2」が参照するArrayListの場所が上書きされています。
「ByRef」の場合は、関数内で引数を書き換えてしまうと、最初に渡されてきたデータの参照が どこかに行ってしまい、宙ぶらりんでどこからも参照できなくなる可能性がありますので、注意が必要です。
■関連記事
⇒VB.NETの関数の戻り値が参照型について
⇒VB.NETの配列のReDimについて
⇒VB.NETの配列は参照型
⇒VB.NETの値型と参照型について
⇒VB.NETの文字列型(String)について