1

イベント ハンドラーを動的にアタッチ/デタッチする利点はありますか?

ハンドラーを手動でデタッチすると、破棄されたオブジェクトへの参照が残っていないことを確認できますか?

4

7 に答える 7

3

Handlesこの句は単なる構文糖衣であり、AddHandlerステートメントをコンストラクターに挿入するものであると確信しています。このコードを使用してテストし、アプリケーション フレームワークを無効にして、コンストラクターに余分なものがないようにしました。


Public Class Form1

    Public Sub New()
        ' This call is required by the Windows Form Designer. '
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call. '
        AddHandler Me.Load, AddressOf Form1_Load
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim breakpoint As Integer = 4
    End Sub
End Class

ILは次のようになりました。

  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  call       instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
  IL_0007:  nop
  IL_0008:  ldarg.0
  IL_0009:  ldarg.0
  IL_000a:  dup
  IL_000b:  ldvirtftn  instance void WindowsApplication1.Form1::Form1_Load(object,
                                                                           class [mscorlib]System.EventArgs)
  IL_0011:  newobj     instance void [mscorlib]System.EventHandler::.ctor(object,
                                                                          native int)
  IL_0016:  call       instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler)

 '... lots of lines here '

  IL_0047:  ldarg.0
  IL_0048:  callvirt   instance void WindowsApplication1.Form1::InitializeComponent()
  IL_004d:  nop
  IL_004e:  ldarg.0
  IL_004f:  ldarg.0
  IL_0050:  dup
  IL_0051:  ldvirtftn  instance void WindowsApplication1.Form1::Form1_Load(object,
                                                                           class [mscorlib]System.EventArgs)
  IL_0057:  newobj     instance void [mscorlib]System.EventHandler::.ctor(object,
                                                                          native int)
  IL_005c:  callvirt   instance void [System.Windows.Forms]System.Windows.Forms.Form::add_Load(class [mscorlib]System.EventHandler)
  IL_0061:  nop
  IL_0062:  nop
  IL_0063:  ret
} // end of method Form1::.ctor

IL_000b と IL_0051 の周りに 2 つの同一のコード ブロックがあることに注意してください。私はそれが単なる構文糖だと思います。

于 2008-09-11T20:53:23.513 に答える
2

フィールドを as として宣言するWithEventsと、コンパイラはその名前のプロパティを自動的に生成します。ゲッターはバッキング フィールドの値を返します。セッターはもう少し複雑です。最初に、バッキング フィールドに既に正しい値があるかどうかを確認します。もしそうなら、それは終了します。それ以外の場合、バッキング フィールドが null でない場合は、バッキング フィールドによって識別されるオブジェクトに対して、そのすべてのイベントに対する「RemoveHandler」リクエストを発行します。次に、バッキング フィールドが null ではないかどうかに関係なく、要求された値と等しくなるように設定します。最後に、新しい値が null でない場合、古い値がそうであったかどうかに関係なく、プロパティは、新しい値によって識別されるオブジェクトに対して、そのすべてのイベントに対して "AddHandler" 要求を発行します。

オブジェクトを放棄する前にオブジェクトのすべての WithEvents メンバーを に設定しNothing、複数のスレッドで WithEvents メンバーを操作しないようにすれば、自動生成されたイベント コードはリークしません。

于 2013-10-10T21:15:27.323 に答える
2

AddHandler と Handles のどちらを使用するかという問題ではありません。

イベント ハンドラーへの参照がガベージ コレクションに干渉することが懸念される場合は、ハンドラーがどのようにアタッチされたかに関係なく、RemoveHandler を使用する必要があります。フォームまたはコントロールの Dispose メソッドで、ハンドラーをすべて削除します。

Windows フォーム アプリ (.NET 1.1 日) で、他の参照を持たないコントロールでイベント ハンドラーが呼び出される状況がありました (そして、すべての意図と目的のために死んでいて、GC されたと思っていたでしょう)。 -- デバッグが非常に困難です。

再利用しないコントロールのハンドラーを削除するには、RemoveHandler を使用します。

于 2008-09-11T21:04:42.253 に答える
1

コントロールを手動で作成するときにハンドラーを手動でアタッチします (たとえば、データベース レコードごとに TextBox を動的に作成するなど)。まだ処理する準備が整っていないものをハンドラーが処理しているときは、ハンドラーを手動でデタッチします (おそらく、間違ったイベントを使用しているためですか? :))

于 2008-09-16T17:06:02.583 に答える
1

イベント ハンドラーを動的にアタッチ/デタッチするのは、寿命の長いオブジェクトが多くの寿命の短いオブジェクトによって消費されるイベントを公開している場合にのみ使用できることがわかりました。他のほとんどの場合、2 つのオブジェクトはほぼ同時に破棄され、CLR は独自にクリーンアップするのに十分な作業を行います。

于 2008-09-11T20:50:43.770 に答える
0

ほとんどの場合、フレームワークがそれを処理します。

于 2008-09-11T20:42:23.540 に答える
0

イベントを手動でデタッチすることは、メモリ リークを防ぐために重要な場合があります。別のオブジェクトによって起動されたイベントに接続するオブジェクトは、イベントを起動したオブジェクトがガベージ コレクションされるまでガベージ コレクションされません。言い換えれば、「イベント発生器」は、それに接続されているすべての「イベントリスナー」への強力な参照を持っています。

于 2008-09-11T20:48:26.707 に答える