ITコンサルの日常

ITコンサル会社に勤務する普通のITエンジニアの日常です。

VB.NETのByValとByRefについて

結論、こうなるらしい。

- ByVal ByRef
値型 値渡し 参照渡し
参照型 参照渡し参照の値渡し 参照渡し

つまり、参照型を引数として受け取るFunctionやSubは、どっちにしても参照渡しになるという罠。


(5/28)id:bleis-tiftさんに指摘されて直しました。


ちなみにどれが値型で、どれが参照型かというのは、
http://msdn.microsoft.com/ja-jp/library/dd314344.aspx
に書いてありました。
Dateが値型とか、Javaな人にとってはハマりそうなポイントかも。


なわけで、サンプル書いてみた。

値型

Class Test
       Public Shared Sub Main()
               Dim i = 20

               ' ByValで渡す
               ByValFunction(i)
               System.Console.WriteLine("i = " & i)

               ' ByRefで渡す
               ByRefFunction(i)
               System.Console.WriteLine("i = " & i)
       End Sub

       ' 値渡しで受け取る関数
       Private Shared Sub ByValFunction(ByVal i As Integer)
               i = i + 1
       End Sub

       ' 参照渡しで受け取る関数
       Private Shared Sub ByRefFunction(ByRef i As Integer)
               i = i + 2
       End Sub
End Class

結果はこう。

i = 20
i = 22

上は値渡しなので、呼び出し先で値を変えても、呼び出し元には影響なし。
下は参照渡しなので、呼び出し先で値を変えると、呼び出し元にも影響する。

参照型

Class Test
      Public Shared Sub Main()
              ' Personオブジェクトを作成
              Dim p = New Person
              p.name = "aaa"
              p.age = 20
              p.Show()

              ' ByValで渡す
              ByValFunction(p)
              p.Show()

              ' ByRefで渡す
              ByRefFunction(p)
              p.Show()

              ' ByValで渡す
              ByValFunction2(p)
              p.Show()

              ' ByRefで渡す
              ByRefFunction2(p)
              p.Show()
      End Sub

      ' 値渡しで受け取る関数
      Private Shared Sub ByValFunction(ByVal p As Person)
              ' 参照型の値を書き換える
              p.name = "bbb"
              p.age = p.age + 1
      End Sub

      ' 参照渡しで受け取る関数
      Private Shared Sub ByRefFunction(ByRef p As Person)
              ' 参照型の値を書き換える
              p.name = "ccc"
              p.age = p.age + 2
      End Sub

      ' 値渡しで受け取る関数
      Private Shared Sub ByValFunction2(ByVal p As Person)
              ' 参照型の参照を書き換える
              Dim other = New Person
              other.name = "ccc"
              other.age = 30
              p = other
      End Sub

      ' 参照渡しで受け取る関数
      Private Shared Sub ByRefFunction2(ByRef p As Person)
              ' 参照型の参照を書き換える
              Dim other = New Person
              other.name = "ddd"
              other.age = 40
              p = other
      End Sub
End Class

' Personモデル
Class Person
      Public name As String
      Public age As Integer

      Public Sub Show()
              System.Console.WriteLine(name & ":" & age)
      End Sub
End Class

結果はこう。

aaa:20
bbb:21
ccc:23
ccc:23
ddd:40

ByValにしようが、ByRefにしようが、参照渡しになっています。
ってことは結局ByRefなのだから、コンパイラでワーニング出して欲しいところですね。
VS2003でも、VS2008でも、ワーニング出ませんでしたが。。


参照型を渡したときのByValとByRefの違いが分りづらいですが(僕も分ってませんでしたが)、
図解すると、どうもこういうことらしい?