1

IDisposable を実装すると、VS はこれらのリージョン化されたプロシージャを自動的に生成します。

#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: dispose managed state (managed objects).
            End If

            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' TODO: set large fields to null.
        End If
        Me.disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
    'Protected Overrides Sub Finalize()
    '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    '    Dispose(False)
    '    MyBase.Finalize()
    'End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

クラスに 1 つの使い捨てオブジェクト (プロセス クラスからの新しいプロセス) があり、それが決して閉じられたり破棄されたりしないと想像してください。そのため、クラスに IDisposable を実装して破棄したいと考えています...

私の質問は次のとおりです。

  • 上記のコードのどの行に ?を入力する必要がありmyProcess.Dispose()ますか?

  • たとえば、使い捨てではないString変数とInteger変数がいくつかdim myVar as string = "value"あります。使い捨てオブジェクトを破棄するときに、これらの変数の値を null 値にするとよいでしょうか? このようなもの?:

    sub dispose()
      myProcess.Dispose()
      myvar = nothing
    end sub
    
  • 私のクラスはいくつかの WinAPI 関数を呼び出し、メッセージを解析するために WndProc サブルーチンもオーバーライドします。ファイナライザーを使用する必要があるか、SuppressFinalize を使用できますか? Finalizeサブのコメントを外すだけで、それだけですか?. Finalizer の目的や、いつ、どのように使用する必要があるのか​​わかりません。


Dispose メソッドを実装する正しい方法が正確にはわかりませんが、この方法で破棄していますが、いずれかの方法で完全に間違っていることは確かです...:

#Region " Dispose "

    ''' <summary>
    ''' Disposes all the objects created by this class.
    ''' </summary>
    Public Sub Dispose() _
    Implements IDisposable.Dispose

        ' Process
        p.Dispose() 

        ' Public Properties
        Me.mp3val_location = Nothing
        Me.CheckFileExist = Nothing

        ' String variables
        StandardError = Nothing
        StandardOutput = Nothing
        Info = Nothing
        Warnings = Nothing
        Errors = Nothing
        Tags = Nothing

        ' RegEx variables
        Info_RegEx = Nothing
        Warning_RegEx = Nothing
        Fixed_RegEx = Nothing

        ' EventArgs Variables
        StartedArgs = Nothing
        ExitedArgs = Nothing

        GC.SuppressFinalize(Me)

    End Sub

#End Region

アップデート

だから...混乱するVS生成コードを単純化して、私の要求についてより直感的で使いやすいようにするには、次のように使用する必要がありますか?:

Public Class Test : Implements IDisposable

Public Sub Dispose() Implements IDisposable.Dispose
    Dispose(True)
    GC.SuppressFinalize(Me)
End Sub

Protected Overridable Sub Dispose(IsDisposing As Boolean)

    Static IsBusy As Boolean ' To detect redundant calls.

    If Not IsBusy AndAlso IsDisposing Then

        ' Dispose processes here...
        ' myProcess.Dispose()

    End If

    IsBusy = True

End Sub

End Class
4

1 に答える 1

1

上記のコードの正確にどの行に myProcess.Dispose() を配置する必要がありますか

なし。あなたはそうしない。すべきことは、usingブロックの一部としてクラスのインスタンスを作成することです。Dispose()これにより、適切な時間に自動的に呼び出されます。それができない場合は、常にブロックの一部としてクラスを作成し、ブロックの一部としてtry呼び出します。Dispose()finally

使い捨てオブジェクトを破棄するときに、これらの vars の値を null 値にすると良いでしょうか?

いいえ、必要ありません。String 変数と int 変数はメモリのみを使用し、ガベージ コレクター余分な作業を行わずにこれらを正しく処理します。

私のクラスはいくつかの WinAPI 関数を呼び出し、メッセージを解析するために WndProc サブルーチンもオーバーライドします。ファイナライザーを使用する必要があるか、SuppressFinalize を使用できますか?

WinAPI 呼び出しがファイル ハンドル、gdi ハンドル、スレッド、ソケットなどのシステム リソースを割り当てる場合、およびこれらのリソースの解放を処理する既存の .Net クラスの一部ではない場合、ファイナライザーが必要です。これらの条件の両方が true の場合にのみ、ファイナライザーが必要です。非常に多くの場合、ファイナライザーは.Dispose(False)、コメント付きの例に示すようにメソッドを呼び出すだけなので、クリーンアップ コードは 1 つの場所に存在するだけで済みます。

したがって、IDisposable を実装するときは、ほとんどの場合、そのサンプルの最初のメソッドだけを考慮する必要があります。Finalize() メソッドのコメントを外すこともできますが、それだけです。それでは、その方法を見てみましょう。

' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
    If Not Me.disposedValue Then
        If disposing Then
            ' TODO: dispose managed state (managed objects).
        End If

        ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
        ' TODO: set large fields to null.
    End If
    Me.disposedValue = True
End Sub

ここでの秘訣は、TODO コメントが紛らわしいことです...誤解を招くことさえあります。最初のコメント (「管理された状態を破棄する」) は、管理された状態を自分で破棄することはできないため、まったく価値がありません。これは完全にガベージ コレクター次第です。それを念頭に置いて、 if 条件を完全に削除できます。このルールの唯一の例外は、イベント ハンドラーです。この場所を使用して、クラス内のデリゲートの登録を解除できます。

2 番目の TODO コメント (「管理されていないリソースを解放する」) の方が便利です。アンマネージ リソースのクリーンアップ コードを配置する場所が示されます。それはあまりにも長く続きます。最初のフレーズの後で止まると、より明確になります。クラス自体が IDisposable クラスのインスタンスをラップする場合、これはオブジェクトに対して .Dipose() を呼び出すのに適した場所です。

3 番目の TODO コメント (「大きなフィールドを null に設定」) もほとんど不要です。通常、.Net で項目を NULL に設定してもまったく役に立ちません。この場合、既にオブジェクトを破棄しています。これは、いずれにせよスコープから外れる可能性が非常に高く、GC が次に実行されたときに、それらのオブジェクトが引き続きコレクションの対象となることを意味します。これを行う唯一の理由は、オブジェクトが破棄された後すぐにスコープ外に出ないことが疑われる場合です。その場合、これらのフィールドを null に設定すると、より大きなメモリ ブロックをより早く収集できるようになる可能性がありますが、この状況は、クラスのユーザーによる設計が不十分であることを示しています。

于 2013-11-10T22:34:41.417 に答える