関数の戻り値として、関数内でクラスのインスタンスを New で生成しその参照を戻す場合があります。 この場合、戻されたその参照の実体はどこにあるのでしょうか。これなのですがVB.NETシステムのヒープ領域のメモリ上に在る様です。 このメモリ上の参照しているのが New で生成された結果の値を保持する変数になります。
以下のソースにその例を示します。
frmRetval と名付けたフォーム上に1個のボタンを張り付けてあります。 このフォームクラス内に、戻り値テスト用のクラスとして clsRetTest を宣言しています。 このクラスは2個の内部変数とその内容を文字列で返すメソッド、及びコンストラクタの簡単な処理から構成します。
更にクラス clsRetTest を戻す関数として GetRetVal 関数を定義しています。
戻り値テスト用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | Public Class frmRetval '戻り値テスト用のクラス Private Class clsRetTest Private _strTest As String Private _intTest As Integer 'コンストラクタ Sub New ( ByVal strTest As String , ByVal intTest As Integer ) Me ._strTest = strTest Me ._intTest = intTest End Sub '内部データの表示用の文字列取得 Function GetDataString() As String Return "strTest=" & Me ._strTest & vbCrLf & "intTest=" & Me ._intTest.ToString End Function End Class 'クラスを戻す関数をテストする処理 Private Sub RetrunTest_Click(sender As Object , e As EventArgs) Handles RetrunTest.Click 'クラスを生成する関数コール Dim clsTest As clsRetTest = GetRetVal() '内部データの表示 MsgBox(clsTest.GetDataString) End Sub 'クラス(clsRetTest)を戻す関数 Private Function GetRetVal() As clsRetTest 'クラスの生成 Dim clsRet As New clsRetTest( "123" , 100) 'クラスを戻す Return clsRet End Function End Class |
クラスを戻す関数をテストするのは、ボタンクリックイベントで行っています。 このイベントでは、クラスを生成する関数(GetRetVal)をコールし結果を clsTest 変数に入れています。 GetRetVal の中ではクラス clsRetTest がインスタンスがヒープ上に生成されその参照を戻り値として戻します。 イベント処理内ではその参照を使い、そのメソッドをコールすることができます。
このイベント処理内の変数 clsTest はこの処理を抜けると使用できなくなります。 (自動変数はそれ自身を含むブロックを超えては参照が出来ません。)
clsTest は使用できなくなるのは分かるのですが、先ほどのヒープ上の clsRetTest クラスの領域はどうなるのでしょうか。 少し心配になりますが、実はシステム側である時点が来た時にきれいに掃除をしてくれます。 (このことをガーベージコレクションと言うらしい。)
ボタンクリックが何度も押されると RetrunTest_Click が何度も実行されることになります。 この時はその度に、ヒープ上に別のインスタンスが生成され、そのインスタンスの参照が返されます。 そうすると使わないインスタンスがどんどん溜まっていくのですが、これもそのうちガーベージコレクションが行われて無くなる様です。 (ガーベージコレクションがいつ行われるかは神のみぞ知る的な感じな様ですが)
イベント処理内の clsTest がイベント処理が終わった後でも参照したい場合には、 その変数を以下のソースの様に、イベント処理内からフォームクラスの静的変数として関数の外で宣言すればできます。
クラス参照を静的変数で宣言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | Public Class frmRetval '戻り値テスト用のクラス Private Class clsRetTest Private _strTest As String Private _intTest As Integer 'コンストラクタ Sub New ( ByVal strTest As String , ByVal intTest As Integer ) Me ._strTest = strTest Me ._intTest = intTest End Sub '内部データの表示用の文字列取得 Function GetDataString() As String Return "strTest=" & Me ._strTest & vbCrLf & "intTest=" & Me ._intTest.ToString End Function End Class 'クラス参照宣言 Dim clsTest As clsRetTest 'クラスを戻す関数をテストする処理 Private Sub RetrunTest_Click(sender As Object , e As EventArgs) Handles RetrunTest.Click 'クラスを生成する関数コール clsTest = GetRetVal() '内部データの表示 MsgBox(clsTest.GetDataString) End Sub 'クラス(clsRetTest)を戻す関数 Private Function GetRetVal() As clsRetTest 'クラスの生成 Dim clsRet As New clsRetTest( "123" , 100) 'クラスを戻す Return clsRet End Function 'クラスのメソッドのみをコールするイベント Private Sub DisplayClass_Click(sender As Object , e As EventArgs) Handles DisplayClass.Click '内部データの表示 MsgBox(clsTest.GetDataString) End Sub End Class |
clsTest をフォームクラスの静的変数として宣言すれば、そこに設定されたヒープへの参照が残りますので、 それを使ってクラスの処理ができます。今回の例では、DisplayClass_Click がそれに当たります。
但し、このソースには問題が有ります。 RetrunTest_Click を行う前に DisplayClass_Click を行うと例外が発生してしまいます。 これは、clsTest が設定される前(値としては Nothing)にクラスのメソッドを使用するからです。 この問題を解消するには DisplayClass_Click 内で clsTest が Nothing では無いことを確認し 使用します。
尚、この clsTest ですが何時廃棄されるのかと言いますと、フォームクラスが廃棄される時点で行われ、 その後ガーベージコレクションが行われると思います。
コメント