クラスのインスタンスであるオブジェクトは、 New
キーワードを使用して作成されます。 初期化タスクは、多くの場合、新しいオブジェクトを使用する前に実行する必要があります。 一般的な初期化タスクには、ファイルの開き方、データベースへの接続、レジストリ キーの値の読み取りなどがあります。 Visual Basic では、 コンストラクター (初期化を制御できる特殊なメソッド) と呼ばれるプロシージャを使用して、新しいオブジェクトの初期化を制御します。
オブジェクトがスコープを離れた後、共通言語ランタイム (CLR) によって解放されます。 Visual Basic では、 デストラクターと呼ばれるプロシージャを使用して、システム リソースの解放を制御します。 コンストラクターとデストラクターは共に、堅牢で予測可能なクラス ライブラリの作成をサポートします。
コンストラクターとデストラクターの使用
コンストラクターとデストラクターは、オブジェクトの作成と破棄を制御します。 Visual Basic の Sub New
プロシージャと Sub Finalize
プロシージャは、オブジェクトを初期化して破棄します。Visual Basic 6.0 以前のバージョンで使用されている Class_Initialize
メソッドと Class_Terminate
メソッドを置き換えます。
Sub New
Sub New
コンストラクターは、クラスの作成時に 1 回だけ実行できます。 同じクラスまたは派生クラスから別のコンストラクターのコードの最初の行以外の場所で明示的に呼び出すことはできません。 さらに、 Sub New
メソッドのコードは、常にクラス内の他のコードの前に実行されます。 クラスのSub New
プロシージャを明示的に定義しない場合、Visual Basic は実行時にSub New
コンストラクターを暗黙的に作成します。
クラスのコンストラクターを作成するには、クラス定義内の任意の場所 Sub New
という名前のプロシージャを作成します。 パラメーター化されたコンストラクターを作成するには、次のコードのように、他のプロシージャの引数を指定する場合と同様に、 Sub New
する引数の名前とデータ型を指定します。
Sub New(ByVal s As String)
コンストラクターは、次のコードのように頻繁にオーバーロードされます。
Sub New(ByVal s As String, i As Integer)
別のクラスから派生したクラスを定義する場合、基底クラスにパラメーターを受け取っていないアクセス可能なコンストラクターがない限り、コンストラクターの最初の行は基底クラスのコンストラクターの呼び出しである必要があります。 たとえば、上記のコンストラクターを含む基底クラスの呼び出しは MyBase.New(s)
。 それ以外の場合、 MyBase.New
は省略可能であり、Visual Basic ランタイムによって暗黙的に呼び出されます。
親オブジェクトのコンストラクターを呼び出すコードを記述した後、 Sub New
プロシージャに初期化コードを追加できます。
Sub New
は、パラメーター化されたコンストラクターとして呼び出されたときに引数を受け取ることができます。 これらのパラメーターは、 Dim AnObject As New ThisClass(X)
など、コンストラクターを呼び出すプロシージャから渡されます。
Sub Finalize
オブジェクトを解放する前に、CLR は、Sub Finalize
プロシージャを定義するオブジェクトのFinalize
メソッドを自動的に呼び出します。
Finalize
メソッドには、オブジェクトが破棄される直前に実行する必要があるコード (ファイルを閉じるコードや状態情報を保存するコードなど) を含めることができます。
Sub Finalize
の実行にはパフォーマンスが若干低下するため、オブジェクトを明示的に解放する必要がある場合にのみ、Sub Finalize
メソッドを定義する必要があります。
注
CLR のガベージ コレクターは、CLR 環境の外部で、オペレーティング システムが直接実行する アンマネージ オブジェクト (オブジェクト) を破棄しません (また、破棄できません)。 これは、異なるアンマネージド オブジェクトをさまざまな方法で破棄する必要があるためです。 その情報はアンマネージド オブジェクトに直接関連付けされません。オブジェクトのドキュメントに記載されている必要があります。 アンマネージ オブジェクトを使用するクラスは、その Finalize
メソッドでそれらを破棄する必要があります。
Finalize
デストラクターは、それが属しているクラスまたは派生クラスからのみ呼び出すことができる保護されたメソッドです。 システムは、オブジェクトが破棄されたときにFinalize
自動的に呼び出されるため、派生クラスのFinalize
実装の外部からFinalize
を明示的に呼び出すべきではありません。
オブジェクトが何も設定されるとすぐに実行される Class_Terminate
とは異なり、通常、オブジェクトがスコープを失い、Visual Basic が Finalize
デストラクターを呼び出すまでの間に遅延が発生します。 Visual Basic .NET では、2 番目の種類のデストラクター ( IDisposable.Dispose) を使用できます。これは、リソースをすぐに解放するためにいつでも明示的に呼び出すことができます。
注
Finalize
デストラクターは、アプリケーションで処理できず、アプリケーションが終了する可能性があるため、例外をスローしないでください。
クラス階層での New メソッドと Finalize メソッドの動作
クラスのインスタンスが作成されるたびに、共通言語ランタイム (CLR) は、そのオブジェクトに存在する場合は、 New
という名前のプロシージャの実行を試みます。
New
は、オブジェクト内の他のコードが実行される前に新しいオブジェクトを初期化するために使用される constructor
と呼ばれるプロシージャの一種です。
New
コンストラクターを使用すると、ファイルを開いたり、データベースに接続したり、変数を初期化したり、オブジェクトを使用する前に実行する必要があるその他のタスクを処理したりできます。
派生クラスのインスタンスが作成されると、基底クラスの Sub New
コンストラクターが最初に実行され、次に派生クラスのコンストラクターが実行されます。 これは、 Sub New
コンストラクターのコードの最初の行が構文を使用 MyBase.New()
クラス階層内のクラスのすぐ上にあるクラスのコンストラクターを呼び出すためです。
Sub New
コンストラクターは、基底クラスのコンストラクターに到達するまで、クラス階層内の各クラスに対して呼び出されます。 その時点で、基底クラスのコンストラクター内のコードが実行され、その後、すべての派生クラスの各コンストラクターのコードが実行され、最も派生したクラスのコードが最後に実行されます。
オブジェクトが不要になると、CLR はメモリを解放する前に、そのオブジェクトの Finalize メソッドを呼び出します。
Finalize メソッドは、状態情報の保存、データベースへのファイルと接続の終了、オブジェクトを解放する前に実行する必要があるその他のタスクなどのクリーンアップ タスクを実行するため、destructor
と呼ばれます。
IDisposable インターフェイス
クラス インスタンスは、多くの場合、Windows ハンドルやデータベース接続など、CLR によって管理されないリソースを制御します。 これらのリソースは、ガベージ コレクターによってオブジェクトが破棄されたときに解放されるように、クラスの Finalize
メソッドで破棄する必要があります。 ただし、ガベージ コレクターは、CLR がより多くの空きメモリを必要とする場合にのみオブジェクトを破棄します。 つまり、オブジェクトがスコープ外になるまでリソースが解放されない可能性があります。
ガベージ コレクションを補完するために、クラスは、システム リソースが IDisposable インターフェイスを実装している場合にアクティブに管理するメカニズムを提供できます。
IDisposable には 1 つのメソッド ( Dispose) があり、クライアントはオブジェクトの使用が完了したときに呼び出す必要があります。
Disposeメソッドを使用すると、リソースを直ちに解放し、ファイルやデータベース接続を閉じるなどのタスクを実行できます。
Finalize
デストラクターとは異なり、Dispose メソッドは自動的には呼び出されません。 リソースをすぐに解放する場合、クラスのクライアントは Dispose を明示的に呼び出す必要があります。
IDisposable の実装
IDisposable インターフェイスを実装するクラスには、次のコード セクションを含める必要があります。
オブジェクトが破棄されたかどうかを追跡するためのフィールド:
Protected disposed As Boolean = False
クラスのリソースを解放する Dispose のオーバーロード。 このメソッドは、基底クラスの Dispose メソッドと
Finalize
メソッドによって呼び出される必要があります。Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposed Then If disposing Then ' Insert code to free managed resources. End If ' Insert code to free unmanaged resources. End If Me.disposed = True End Sub
次のコードのみを含む Dispose の実装。
Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub
次のコードのみを含む
Finalize
メソッドのオーバーライド。Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub
IDisposable を実装するクラスからの派生
IDisposable インターフェイスを実装する基底クラスから派生するクラスは、破棄する必要がある追加のリソースを使用しない限り、どの基本メソッドもオーバーライドする必要はありません。 その場合、派生クラスは基底クラスの Dispose(disposing)
メソッドをオーバーライドして、派生クラスのリソースを破棄する必要があります。 このオーバーライドでは、基底クラスの Dispose(disposing)
メソッドを呼び出す必要があります。
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposed Then
If disposing Then
' Insert code to free managed resources.
End If
' Insert code to free unmanaged resources.
End If
MyBase.Dispose(disposing)
End Sub
派生クラスは、基底クラスの Dispose および Finalize
メソッドをオーバーライドしないでください。 これらのメソッドが派生クラスのインスタンスから呼び出されると、これらのメソッドの基底クラスの実装は、派生クラスの Dispose(disposing)
メソッドのオーバーライドを呼び出します。
ガベージ コレクションと Finalize デストラクター
.NET Framework では、 参照トレース ガベージ コレクション システムを使用して、未使用のリソースを定期的に解放します。 Visual Basic 6.0 以前のバージョンでは、 参照カウント と呼ばれる別のシステムを使用してリソースを管理しました。 どちらのシステムも同じ機能を自動的に実行しますが、いくつかの重要な違いがあります。
CLR は、このようなオブジェクトが不要になったとシステムが判断すると、オブジェクトを定期的に破棄します。 オブジェクトは、システム リソースが不足している場合はより迅速に解放され、それ以外の場合はリリース頻度が低くなります。 オブジェクトがスコープを失い、CLR が解放されるまでの遅延は、Visual Basic 6.0 以前のバージョンのオブジェクトとは異なり、オブジェクトが破棄されるタイミングを正確に判断できないことを意味します。 このような状況では、オブジェクトの 有効期間は非決定論的であると言われます。 ほとんどの場合、オブジェクトがスコープを失ったときに、 Finalize
デストラクターが直ちに実行されないことを覚えている限り、非決定論的な有効期間はアプリケーションの記述方法を変更しません。
ガベージ コレクション システムのもう 1 つの違いは、 Nothing
の使用です。 Visual Basic 6.0 以前のバージョンの参照カウントを利用するために、プログラマはオブジェクト変数に Nothing
を割り当てて、保持されている変数の参照を解放する場合があります。 変数がオブジェクトへの最後の参照を保持していた場合、オブジェクトのリソースはすぐに解放されました。 それ以降のバージョンの Visual Basic では、このプロシージャがまだ重要な場合がありますが、これを実行しても、参照先オブジェクトがリソースをすぐに解放することはありません。 リソースをすぐに解放するには、オブジェクトの Dispose メソッド (使用可能な場合) を使用します。 変数を Nothing
に設定する必要があるのは、ガベージ コレクターが孤立したオブジェクトを検出するのにかかる時間に対して有効期間が長い場合だけです。
こちらも参照ください
.NET