オブジェクトの有効期間: オブジェクトの作成と破棄 (Visual Basic)

クラスのインスタンス、つまりオブジェクトを作成するには New キーワードを使用します。通常は、新しいオブジェクトを使用する前に初期化する必要があります。一般的な初期化のタスクとしては、ファイルを開く、データベースに接続する、レジストリ キーの値を読み取るなどがあります。Visual Basic では、新しいオブジェクトの初期化処理をコンストラクターと呼ばれるプロシージャによって制御します。コンストラクターとは、初期化を制御するための特殊なメソッドです。

スコープを離れたオブジェクトは、共通言語ランタイム (CLR: Common Language Runtime) によって解放されます。Visual Basic では、システム リソースの解放をデストラクターと呼ばれるプロシージャによって制御します。コンストラクターとデストラクターは、堅牢で予測可能なクラス ライブラリを作成するのに役立ちます。

コンストラクターとデストラクターの使用方法

コンストラクターとデストラクターは、オブジェクトの構築と破棄を制御します。Visual Basic では、Sub New プロシージャと Sub Finalize プロシージャがオブジェクトの初期化と破棄を行います。これらは、Visual Basic 6.0 以前のバージョンで使用されていた Class_Initialize メソッドと Class_Terminate メソッドに代わるものです。

hks5e2k6.collapse_all(ja-jp,VS.110).gifSub New

Sub New コンストラクターは、クラスの作成時に 1 回だけ実行できます。同じクラスまたは派生クラスの別のコンストラクターの 1 行目に記述して呼び出す以外に、これを明示的に呼び出す方法はありません。また、Sub New メソッド内のコードは常に、クラス内の他のすべてのコードより先に実行されます。クラスの Sub New プロシージャを明示的に定義しなかった場合、Visual Basic 2005 以降のバージョンでは、実行時に Sub New コンストラクターが暗黙的に作成されます。

クラスのコンストラクターを作成するには、クラス定義の任意の場所に Sub New というプロシージャを作成します。パラメーター化されたコンストラクターを作成するには、他のプロシージャと同じように、Sub New への引数の名前とデータ型を指定します。次に、コード例を示します。

Sub New(ByVal s As String)

コンストラクターは、次のコードに示すように、オーバーロードされる場合があります。

Sub New(ByVal s As String, i As Integer)

パラメーターを受け取らないコンストラクターに基本クラスからアクセス可能な場合を除き、他のクラスから派生したクラスを定義するときには、コンストラクターの 1 行目で基本クラスのコンストラクターを呼び出す必要があります。上のコンストラクターを持つ基本クラスの呼び出しは、MyBase.New(s) のようになります。それ以外の場合、MyBase.New は省略可能で、Visual Basic のランタイムが暗黙的に呼び出します。

親オブジェクトのコンストラクターを呼び出すコードを記述したら、Sub New プロシージャに初期化コードを自由に追加できます。Sub New は、パラメーター化されたコンストラクターとして呼び出されると、引数を受け取ることができます。これらのパラメーターは、コンストラクターを呼び出すプロシージャから渡されます。たとえば、Dim AnObject As New ThisClass(X) のように指定します。

hks5e2k6.collapse_all(ja-jp,VS.110).gifSub Finalize

オブジェクトを解放する前に、CLR は Sub Finalize プロシージャを定義するオブジェクトの Finalize メソッドを自動的に呼び出します。Finalize メソッドには、オブジェクトを破棄する直前に実行する必要があるコードを記述できます。これらのコードでは、ファイルを閉じたり、状態情報を保存したりします。Sub Finalize の実行には、わずかながらパフォーマンス上の不利があります。そのため、オブジェクトを明示的に解放する必要がある場合にのみ Sub Finalize メソッドを定義してください。

[!メモ]

オペレーティング システムが CLR 環境の外部で直接実行しているオブジェクトをアンマネージ オブジェクトといいますが、CLR 内のガベージ コレクターはアンマネージ オブジェクトを破棄しません (できません)。これは、アンマネージ オブジェクトは種類ごとに異なる方法で破棄する必要があるからです。そのような情報はアンマネージ オブジェクトに直接関連付けられているわけではなく、オブジェクトのドキュメントで調べる必要があります。アンマネージ オブジェクトを使用するクラスは、Finalize メソッドを使用してオブジェクトを破棄する必要があります。

Finalize デストラクターは、属しているクラスまたは派生クラスからのみ呼び出し可能なプロテクト メソッドです。オブジェクトが破棄されるときに、システムは Finalize を自動的に呼び出します。したがって、派生クラスの Finalize 実装の外部から、明示的に Finalize を呼び出す必要はありません。

オブジェクトが nothing に設定されるとすぐに実行される Class_Terminate とは異なり、通常、オブジェクトがスコープ外になってから Visual Basic が Finalize デストラクターを呼び出すまでには遅延があります。Visual Basic 2005 以降のバージョンには、Dispose というもう 1 種類のデスクトラクターがあります。このデストラクターは、リソースをすぐに解放する必要がある場合にいつでも明示的に呼び出すことができます。

[!メモ]

Finalize デストラクターからは例外をスローしません。アプリケーションは例外を処理できないので、それが原因で異常終了する可能性があります。

hks5e2k6.collapse_all(ja-jp,VS.110).gifクラスの階層構造における New メソッドと Finalize メソッドの動作

クラスのインスタンスが作成されると、共通言語ランタイム (CLR) は、New という名前のプロシージャがオブジェクト内に存在すれば、それを実行しようと試みます。New は、constructor と呼ばれるプロシージャの一種です。これは、オブジェクト内の他のコードを実行する前に、新しいオブジェクトを初期化するために使用されます。New コンストラクターを使用すると、ファイルを開いたり、データベースに接続したり、変数を初期化するなど、オブジェクトを使用できるようにするために事前に実行する必要があるタスクを処理できます。

派生クラスのインスタンスが作成されるときには、まず基本クラスの Sub New コンストラクターが実行され、その後に派生クラスのコンストラクターが実行されます。これは、Sub New コンストラクターのコードの最初の行が、MyBase.New() 構文を使用して、クラスの階層構造でこのクラスのすぐ上のクラスのコンストラクターを呼び出すためです。基本クラスのコンストラクターにたどり着くまで、クラスの階層構造の各クラスに対して Sub New コンストラクターが呼び出されます。基本クラスにたどり着くと、基本クラスのコンストラクターのコードが実行され、続いてすべての派生クラスの各コンストラクターのコードが実行されます。最後に実行されるのは、最派生クラスのコードです。

コンストラクターと継承

オブジェクトが不要になると、CLR は、メモリを解放する前にそのオブジェクトの Finalize メソッドを呼び出します。Finalize メソッドは、状態情報を保存したり、ファイルとデータベースへの接続を閉じるなど、オブジェクトを解放する前に実行する必要があるクリーンアップ タスクを処理するため、destructor と呼ばれます。

コンストラクター Inheritance2

IDisposable インターフェイス

クラス インスタンスは、Windows ハンドルやデータベース接続など、CLR では管理されないリソースを制御する場合があります。このようなリソースはクラスの Finalize メソッド内で破棄する必要があります。これにより、オブジェクトがガベージ コレクターによって破棄されるときにリソースが解放されます。ただし、ガベージ コレクターがオブジェクトを破棄するのは、CLR がより多くの空きメモリを必要とするときに限られます。そのため、オブジェクトがスコープ外になった後、しばらく経ってもリソースが解放されない可能性があります。

クラスが IDisposable インターフェイスを実装している場合は、ガベージ コレクションを補うために、システム リソースをアクティブに管理するしくみを用意できます。IDisposable には、クライアントがオブジェクトの使用を終了するときに呼び出す Dispose メソッドが含まれています。Dispose メソッドを使用すると、即座にリソースを解放して、ファイルやデータベース接続を閉じるなどのタスクを実行できます。Finalize デストラクターとは異なり、Dispose メソッドは自動的には呼び出されません。クラスのクライアントは、リソースを即座に解放するときに、明示的に Dispose を呼び出す必要があります。

hks5e2k6.collapse_all(ja-jp,VS.110).gifIDisposable の実装

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
    

hks5e2k6.collapse_all(ja-jp,VS.110).gifIDisposable を実装するクラスからの派生

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 デストラクターがすぐに実行されない場合があることを覚えている限り、未決定の有効期間を考慮してアプリケーションの記述方法を変える必要はありません。

ガベージ コレクション システムとの違いは、Nothing の使用方法にもあります。Visual Basic 6.0 以前の参照カウント システムを利用するには、オブジェクト変数に Nothing を代入することで、その変数に保持されている参照を解放するという方法があります。この変数がオブジェクトへの最後の参照を保持している場合、オブジェクトのリソースは直ちに解放されます。現在のバージョンの Visual Basic では、この方法が有効な場合もありますが、参照されたオブジェクトのリソースはすぐには解放されません。リソースを直ちに解放するためには、オブジェクトの Dispose メソッドを使用します (使用可能な場合)。変数を Nothing に設定する必要があるのは、ガベージ コレクターが孤立したオブジェクトを検出するまでにかかる時間よりも、変数の有効期間が長い場合だけです。

参照

関連項目

New 演算子 (Visual Basic)

Dispose

Nothing (Visual Basic)

概念

コンポーネントの初期化と終了

Finalize メソッドおよびデストラクター