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の違いが分りづらいですが(僕も分ってませんでしたが)、
図解すると、どうもこういうことらしい?