クラスが動かない への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 こじろー  (社会人)
投稿日時
2022/1/18 11:41:32
ByRefに直すことで、正確に動きました。
VS2019で、web作成の時には、ByValで動いたのですが・・・。
ありがとうございました。
、
VS2019で、web作成の時には、ByValで動いたのですが・・・。
ありがとうございました。
、
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2022/1/18 10:46:06
引数の内容を差し替えるような場合は、
ByVal キーワードによる「値渡し」ではなく
ByRef キーワードによる「参照渡し」を用います。
ただし、参照渡しを用いるメソッド設計はあまり行われません。
実際 .NET Framework のライブラリの中でも、ごく限られたケースでしか使われていません。
(「Integer.TryParse メソッド」や「Interlocked.Exchange メソッド」など)
これは、呼び出し側から見た時に、値が書き換えられたことが視覚的に分かりにくい上に、
受け渡しのために必ず変数を用意しなければならないという使いにくさによるものです。
そのため参照渡しを使って引数を直接書き換えるのではなく、
戻り値を用いて結果を返す方が一般的です。
あるいは《値型》ではなく《参照型》を引数として引き渡し、
その参照型のメンバーを編集する方法もあります。これなら ByVal でも動きます。
ByVal キーワードによる「値渡し」ではなく
ByRef キーワードによる「参照渡し」を用います。
Public Sub out(ByRef a As Integer, ByRef b As Integer)
ただし、参照渡しを用いるメソッド設計はあまり行われません。
実際 .NET Framework のライブラリの中でも、ごく限られたケースでしか使われていません。
(「Integer.TryParse メソッド」や「Interlocked.Exchange メソッド」など)
これは、呼び出し側から見た時に、値が書き換えられたことが視覚的に分かりにくい上に、
受け渡しのために必ず変数を用意しなければならないという使いにくさによるものです。
そのため参照渡しを使って引数を直接書き換えるのではなく、
戻り値を用いて結果を返す方が一般的です。
Module Module1
Sub Main()
Dim a As Integer = 2
Dim b As Integer = 5
'この書き方なら、a, b というデータをもとにして、
'左辺の変数が書き換えられるという事が明確になります
Dim result = Example1(a, b)
MsgBox(result.Item1)
MsgBox(result.Item2)
Dim results() = Example2(a, b)
MsgBox(results(0))
MsgBox(results(1))
'この書き方だと、呼び出し元のコードを見ただけでは、
'a, b のデータが書き換わることが分かりにくいです
Out(a, b)
MsgBox(a)
MsgBox(b)
End Sub
'複数の値を返すためにタプルを使う場合
Public Function Example1(a As Integer, b As Integer) As Tuple(Of Integer, Integer)
Return Tuple.Create(CInt(a ^ 2), CInt(b ^ 2))
End Function
'複数の値を返すために配列を使う場合
Public Function Example2(a As Integer, b As Integer) As Integer()
Return {CInt(a ^ 2), CInt(b ^ 2)}
End Function
'引数の内容を差し替えるために ByRef を使う場合
Public Sub Out(ByRef a As Integer, ByRef b As Integer)
a = a ^ 2
b = b ^ 2
End Sub
End Module
あるいは《値型》ではなく《参照型》を引数として引き渡し、
その参照型のメンバーを編集する方法もあります。これなら ByVal でも動きます。
投稿者 こじろー  (社会人)
投稿日時
2022/1/18 09:23:50
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim class1 As New class1
Dim a As Integer = 2
Dim b As Integer = 5
class1.out(a, b)
MsgBox(a)
MsgBox(b)
End Sub
Public Class class1
Public Sub out(ByVal a As Integer, ByVal b As Integer)
a =a^2
b =b^2
End Sub
End Class
で、a,bは2と5のままで、a=4やb=25になりません。
何かが足りないのでしょうか、VB2013です。
Dim class1 As New class1
Dim a As Integer = 2
Dim b As Integer = 5
class1.out(a, b)
MsgBox(a)
MsgBox(b)
End Sub
Public Class class1
Public Sub out(ByVal a As Integer, ByVal b As Integer)
a =a^2
b =b^2
End Sub
End Class
で、a,bは2と5のままで、a=4やb=25になりません。
何かが足りないのでしょうか、VB2013です。
VB6 だろうと VB2022 だろうと、
Web だろうと Console だろうと WinForm だろうと、
すべて同じルールですよ?
ByVal で動いていたというのであれば、その時渡していたのは
Integer などの「構造体」(つまり《値型》)ではなく、
Model などの「クラス」(つまり《参照型》)だったのではないでしょうか。
>> あるいは《値型》ではなく《参照型》を引数として引き渡し、
>> その参照型のメンバーを編集する方法もあります。これなら ByVal でも動きます。
この辺は基本的な事項なので、一応実験コードを載せておきます。
ByVal は「値のコピー」を渡す作業なので、
メソッド側で値型の仮引数を変更しても、呼び出し側の実引数は変化しません。(v1)
メソッド側で値型の仮引数に別の値をセットしても、呼び出し側の変数は差し替わりません。(v2)
ByRef は「元の変数そのもの」の参照が引き渡されるので、
メソッド側で値型の仮引数を変更すると、呼び出し側の実引数も直接変更されます。(v3)
メソッド側で値型の仮引数に別のオブジェクトをセットすると、呼び出し側の変数も差し替わります。(v4)
また、「参照型」はデータの実体(インスタンス)への参照です。
ByRef では「参照情報そのもの」が渡されますが、
ByVal では「参照情報のコピー」が渡されます。
ByVal では、データそのものがコピーされたわけでは無く、
同一データに対する「参照情報」のみがコピーされただけなので、
参照先のデータは完全に同一インスタンスです。
そのため、ByVal でも ByRef でも、メソッド側で参照型オブジェクトのプロパティを書き換えれば、
呼び出し側でも、同一インスタンスのプロパティが書き換わります。(c1、c3)
メソッド側で参照型の仮引数に別のオブジェクトをセットした場合、
ByRef では「元の変数そのもの」の参照情報が差し替わります。(c4)
しかし ByVal では「コピーされた別変数」の参照情報が差し替わるだけなので、
呼び出し元の変数の参照情報は差し替わりません。(c2)