문제

이벤트 핸들러를 동적으로 연결/분리하면 이점이 있나요?

핸들러를 수동으로 분리하면 삭제된 객체에 대한 참조가 남아 있지 않은지 확인하는 데 도움이 됩니까?

도움이 되었습니까?

해결책

AddHandler와 Handles를 사용하는 문제는 아닙니다.

가비지 수집을 방해하는 이벤트 핸들러에 대한 참조가 우려되는 경우 핸들러 연결 방식에 관계없이 RemoveHandler를 사용해야 합니다.양식이나 컨트롤의 Dispose 메서드에서 모든 처리기를 제거합니다.

Windows Forms 앱(.NET 1.1일)에서 다른 참조가 없는 컨트롤에 대해 이벤트 핸들러가 호출되는 상황이 발생했습니다(그리고 모든 의도와 목적이 죽었고 GC된 것으로 생각했을 것입니다). -- 디버그하기가 매우 어렵습니다.

재사용하지 않을 컨트롤의 핸들러를 제거하려면 RemoveHandler를 사용하겠습니다.

다른 팁

나는 다음과 같은 점을 확신한다. 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 주위에 두 개의 동일한 코드 블록이 있습니다.나는 그것이 단지 구문 설탕이라고 생각합니다.

필드를 다음과 같이 선언 WithEvents 컴파일러가 해당 이름의 속성을 자동으로 생성하게 됩니다.getter는 지원 필드의 값을 반환합니다.세터는 조금 더 복잡합니다.먼저 지원 필드에 이미 올바른 값이 있는지 확인합니다.그렇다면 종료됩니다.그렇지 않고 지원 필드가 null이 아닌 경우 지원 필드로 식별된 개체에 대한 모든 이벤트에 대한 "RemoveHandler" 요청을 발행합니다.다음으로 지원 필드가 null이 아닌지 여부에 관계없이 요청된 값과 동일하게 설정합니다.마지막으로, 새 값이 null이 아닌 경우 이전 값이 null이었는지 여부에 관계없이 속성은 새 값으로 식별되는 객체에 대한 모든 이벤트에 대한 "AddHandler" 요청을 발행합니다.

객체의 모든 WithEvents 멤버를 다음으로 설정한 경우 Nothing 이를 포기하기 전에 여러 스레드에서 WithEvents 멤버를 조작하는 것을 방지하면 자동 생성된 이벤트 코드가 누출되지 않습니다.

이벤트 핸들러를 동적으로 연결/분리하는 것은 수명이 긴 개체가 많은 단기 개체에서 사용되는 이벤트를 노출하는 경우에만 사용된다는 것을 알았습니다.대부분의 경우 두 개체는 거의 동시에 삭제되며 CLR은 자체적으로 충분한 정리 작업을 수행합니다.

컨트롤을 수동으로 생성할 때 핸들러를 수동으로 연결합니다(예: 각 데이터베이스 레코드에 대해 TextBox를 동적으로 생성).아직 처리할 준비가 되지 않은 작업을 처리할 때 핸들러를 수동으로 분리합니다(아마 잘못된 이벤트를 사용하고 있기 때문일까요?):) )

메모리 누수를 방지하려면 이벤트를 수동으로 분리하는 것이 중요할 수 있습니다.다른 개체에 의해 발생된 이벤트에 연결되는 개체는 해당 이벤트를 발생시키는 개체가 가비지 수집될 때까지 가비지 수집되지 않습니다.즉, "이벤트 발생자"는 연결된 모든 "이벤트 리스너"에 대한 강력한 참조를 갖습니다.

대부분의 경우 프레임워크가 이를 처리합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top