by WebSurfer
2019年1月20日 12:37
Visual Basic .NET (VB.NET) のメソッドの引数の値渡し (ByVal) / 参照渡し (ByRef) と、変数の値型 / 参照型をそれらの引数に渡す場合の違いについて、このように考えると理解しやすいと思っていることを書きます。
ちなみに、C# では ByVal に相当するキーワードがなくデフォルトで値渡しになるだけで、考え方は同じです。(ByRef に相当する ref というキーワードはあります)
まず、メソッドの引数に付与する ByVal, ByRef の違いですが、メソッドの呼び出し元から引数に値を渡す時、以下のようしていると考えれば良いと思います。
-
ByVal: 別の入れ物に中身をコピーして渡す
-
ByRef: 入れ物を中身ごと渡す
上記で「入れ物」というのは、例えば、Dim X As Integer で宣言された変数 X で、「中身」というのは X = 10 のようにして変数 X に代入された値 10 のことです。
次に、変数の値型・参照型ですが、クラスや配列は参照型、Integer のような構造体は値型になります。詳しくは、3-2 値型と参照型を見てください。
メソッドに ByVal, ByRef どちらで渡そうと、変数の参照型が値型に変わったり、値型が参照型に変わることはありません。
という訳で、以下の 4 つのケースに分けて考えると良いと思います。
(1) 値型を ByVal で渡す
呼び出し元の入れ物の中身を、メソッド側で用意した別の入れ物に、コピーして渡す。
呼び出し元とメソッドで入れ物が異なるので、メソッド側で入れ物の中身をどのように操作しようと呼び出し元の変数には何の影響もない。
(2) 値型を ByRef で渡す
呼び出し元の入れ物とメソッドに渡された入れ物は同じなので、メソッド側で中身を変更すれば呼び出し側でも中身が変更される。
(3) 参照型を ByVal で渡す
参照型なので渡すのはオブジェクト(インスタンス)を指すアドレス情報。ByVal なのでメソッド側で用意した別の入れ物にアドレス情報をコピーして渡している。
つまり、呼び出し元の変数とメソッド側の変数の中身は同じアドレス情報即ち単一のオブジェクトを指している。
なので、メソッド側で変数が指すオブジェクトを変更すると、呼び出し元の変数が指すオブジェクトでも同じ結果となる。
(4) 参照型を ByRef で渡す
基本は上記 (3) と同じ。
ただし、呼び出し側の入れ物とメソッドに渡された入れ物は同じなので、メソッド側で新しくオブジェクト(インスタンス)を生成してそれのアドレス情報を入れ物に代入すると、呼び出し元の入れ物の中身が指すオブジェクトも、メソッド側で生成した新しいオブジェクトになる。