VB.NETの関数の参照型データの引数での値渡しと参照渡しの違いについて

VB.NETの関数で参照型データ(オブジェクト型)を引数にする場合、値渡しと参照渡しで少し挙動が異なります。
先ず以下のソースを見て下さい。2個の ArrayList 変数を生成し、それぞれ値渡しと参照渡しの値設定関数をコールしています。 「SetArrList1」と「SetArrList2」がコールされる関数ですが、この二つの関数は内部の処理は全く同じ様な処理で 引数の宣言が「ByVal」か「ByRef」かの違いだけです。
「SetArrList1」と「SetArrList2」共に、ArrayListにデータを5個追加する処理をしていますが、 値渡しでも、参照渡しでも渡された引数のArrayListの中のデータが変わることがわかると思います。
「SetArrList1」と「SetArrList2」実行後のデータ表示でそれが分かります。

  1. ' 値渡し・参照渡しのテスト  
  2. Public Shared Sub Main()  
  3.     'ArrayListその1生成  
  4.     Dim Lst1 As New ArrayList  
  5.     'ArrayListその2生成  
  6.     Dim Lst2 As New ArrayList  
  7.   
  8.     '値渡し:参照型データ(引数)への値追加  
  9.     Call SetArrList1(Lst1)  
  10.     '参照渡し:参照型データ(引数)への値追加  
  11.     Call SetArrList2(Lst2)  
  12.   
  13.     Console.WriteLine("*** ArrayListその1全て表示")  
  14.     For i As Integer = 0 To Lst1.Count - 1  
  15.         Console.WriteLine(String.Format("Lst1(" & i & ") = {0}", Lst1(i)))  
  16.     Next  
  17.     Console.WriteLine("*** ArrayListその2全て表示")  
  18.     For i As Integer = 0 To Lst2.Count - 1  
  19.         Console.WriteLine(String.Format("Lst2(" & i & ") = {0}", Lst2(i)))  
  20.     Next  
  21.   
  22. End Sub  
  23.   
  24. ' 値渡し・参照型データ(引数)への値追加  
  25. Private Shared Sub SetArrList1(ByVal List As ArrayList)  
  26.     'ArrayListに要素追加(1 ~ 5)  
  27.     For i As Integer = 1 To 5  
  28.         List.Add(i)  
  29.     Next  
  30. End Sub  
  31.   
  32. ' 参照渡し・参照型データ(引数)への値追加  
  33. Private Shared Sub SetArrList2(ByRef List As ArrayList)  
  34.     'ArrayListに要素追加(11 ~ 15)  
  35.     For i As Integer = 11 To 15  
  36.         List.Add(i)  
  37.     Next  
  38. End Sub  

このソースの実行結果を見てみます。

Rst1


結果からみて注意することは、参照型データを引数で渡す時には値渡しであっても、 その参照型のメソッドを使って参照型の中のデータは変更できるということです。

そこで、次に渡された引数に対して変更を行った場合にはどうなるのかを見てみます。
先ほどのソースに「SetArrList1New」「SetArrList2New」の関数を追加します。 それぞれは内部で、新規にArrayListを生成し、1件のデータを追加後、引数の変数に設定しています。 引数の宣言が「ByVal」か「ByRef」の違いがあるだけです。

  1. ' 値渡し・参照渡しのテスト  
  2. Public Shared Sub Main()  
  3.     'ArrayListその1生成  
  4.     Dim Lst1 As New ArrayList  
  5.     'ArrayListその2生成  
  6.     Dim Lst2 As New ArrayList  
  7.   
  8.     '値渡し:参照型データ(引数)への値追加  
  9.     Call SetArrList1(Lst1)  
  10.     '参照渡し:参照型データ(引数)への値追加  
  11.     Call SetArrList2(Lst2)  
  12.   
  13.     Console.WriteLine("*** ArrayListその1全て表示")  
  14.     For i As Integer = 0 To Lst1.Count - 1  
  15.         Console.WriteLine(String.Format("Lst1(" & i & ") = {0}", Lst1(i)))  
  16.     Next  
  17.     Console.WriteLine("*** ArrayListその2全て表示")  
  18.     For i As Integer = 0 To Lst2.Count - 1  
  19.         Console.WriteLine(String.Format("Lst2(" & i & ") = {0}", Lst2(i)))  
  20.     Next  
  21.   
  22.     Console.WriteLine("****************************")  
  23.     '値渡し:参照型データ(引数)への新規オブジェクト設定  
  24.     Call SetArrList1New(Lst1)  
  25.     '参照渡し:参照型データ(引数)への新規オブジェクト設定  
  26.     Call SetArrList2New(Lst2)  
  27.   
  28.     Console.WriteLine("*** ArrayListその1全て表示")  
  29.     For i As Integer = 0 To Lst1.Count - 1  
  30.         Console.WriteLine(String.Format("Lst1(" & i & ") = {0}", Lst1(i)))  
  31.     Next  
  32.     Console.WriteLine("*** ArrayListその2全て表示")  
  33.     For i As Integer = 0 To Lst2.Count - 1  
  34.         Console.WriteLine(String.Format("Lst2(" & i & ") = {0}", Lst2(i)))  
  35.     Next  
  36. End Sub  
  37.   
  38. ' 値渡し・参照型データ(引数)への値追加  
  39. Private Shared Sub SetArrList1(ByVal List As ArrayList)  
  40.     'ArrayListに要素追加(1 ~ 5)  
  41.     For i As Integer = 1 To 5  
  42.         List.Add(i)  
  43.     Next  
  44. End Sub  
  45.   
  46. ' 参照渡し・参照型データ(引数)への値追加  
  47. Private Shared Sub SetArrList2(ByRef List As ArrayList)  
  48.     'ArrayListに要素追加(11 ~ 15)  
  49.     For i As Integer = 11 To 15  
  50.         List.Add(i)  
  51.     Next  
  52. End Sub  
  53.   
  54. ' 値渡し・関数内でオブジェクトを新規作成し引数に設定  
  55. Private Shared Sub SetArrList1New(ByVal List As ArrayList)  
  56.     Dim ListNew As New ArrayList    'ArrayListの新規生成  
  57.     ListNew.Add(1000)               '1000を値として追加  
  58.     List = ListNew                  '引数に設定  
  59. End Sub  
  60.   
  61. ' 参照渡し・関数内でオブジェクトを新規作成し引数に設定  
  62. Private Shared Sub SetArrList2New(ByRef List As ArrayList)  
  63.     Dim ListNew As New ArrayList    'ArrayListの新規生成  
  64.     ListNew.Add(2000)               '2000を値として追加  
  65.     List = ListNew                  '引数に設定  
  66. End Sub  

Rst2_2


結果から分かることは、「ByVal」の引数ではコール元のArrayListの変数「Lst1」は変化しないことです。 また、「ByRef」の引数の方は、「Lst2」の中身が変わってしまっています。 「Lst2」が参照するArrayListの場所が上書きされています。

「ByRef」の場合は、関数内で引数を書き換えてしまうと、最初に渡されてきたデータの参照が どこかに行ってしまい、宙ぶらりんでどこからも参照できなくなる可能性がありますので、注意が必要です。

■関連記事
VB.NETの関数の戻り値が参照型について
VB.NETの配列のReDimについて
VB.NETの配列は参照型
VB.NETの値型と参照型について
VB.NETの文字列型(String)について


楽天市場

コメント(0)