2009-03-20 5 views
3

다른 개발자 용으로 사용할 클래스 라이브러리를 개발 중이며 WithEvents (또는 다른 언어로 유사)를 사용하여 클래스의 인스턴스를 선언하고 사용하도록 허용 할 예정입니다 클래스에 정의 된 대리자입니다. 이런 식으로 여기서 중복되는 건가요?대리자 사용 및 이벤트 선언

Public Delegate Sub TimerElapsedDelegate(ByVal sender As Object, ByVal e As System.EventArgs) 
Public Event TimerElapsed(ByVal sender As Object, ByVal e As System.EventArgs) 
Private _TimerElapsed As TimerElapsedDelegate = Nothing 

아니면 그냥 이벤트를 선언하고 AddHandler 등을 수행해야합니까?

이것에 대한 조언을 주셔서 감사합니다 ... 나는 중복되고 있다고 생각하고 무의미한 코드를 원하지 않습니다. DRY 원칙을 피할 필요가 없습니다.

그냥 "작업"이 클래스 수행의 인스턴스가 별도의 스레드에서 수행되는 코드의 나머지 부분을 게시하고 싶었, 스트레스 {편집}. {/ 편집}

#Region "Delegates" 
Public Delegate Sub TimerElapsedDelegate(ByVal sender As Object, ByVal e As System.EventArgs) 
Public Event TimerElapsed(ByVal sender As Object, ByVal e As System.EventArgs) 
Private _TimerElapsed As TimerElapsedDelegate = Nothing 
Public Property OnTimerElapsed() As TimerElapsedDelegate 
    Get 
     Return _TimerElapsed 
    End Get 
    Set(ByVal value As TimerElapsedDelegate) 
     If value Is Nothing Then 
      _TimerElapsed = Nothing 
     Else 
      If _TimerElapsed Is Nothing Then 
       _TimerElapsed = value 
      Else 
       _TimerElapsed = System.Delegate.Combine(_TimerElapsed, value) 
      End If 
     End If 
    End Set 
End Property 
Private Sub TriggerTimerElapsed() 
    If OnTimerElapsed IsNot Nothing Then 
     OnTimerElapsed.Invoke(Me, New System.EventArgs) 
    End If 
    RaiseEvent TimerElapsed(Me, New System.EventArgs) 
End Sub 

Public Delegate Sub ItemReadyForQueueDelegate(ByVal sender As Object, ByVal e As System.EventArgs) 
Public Event ItemReadyForQueue(ByVal sender As Object, ByVal e As System.EventArgs) 
Private _ItemReadyForQueue As ItemReadyForQueueDelegate = Nothing 
Public Property OnItemReadyForQueue() As ItemReadyForQueueDelegate 
    Get 
     Return _ItemReadyForQueue 
    End Get 
    Set(ByVal value As ItemReadyForQueueDelegate) 
     If value Is Nothing Then 
      _ItemReadyForQueue = Nothing 
     Else 
      If _ItemReadyForQueue Is Nothing Then 
       _ItemReadyForQueue = value 
      Else 
       _ItemReadyForQueue = System.Delegate.Combine(_ItemReadyForQueue, value) 
      End If 
     End If 
    End Set 
End Property 
Private Sub TriggerItemReadyForQueue(ByVal oItem As h3Budgeteer.FileSystem.ReportTemplateFile.ReportTemplate) 
    If OnItemReadyForQueue IsNot Nothing Then 
     OnItemReadyForQueue.Invoke(Me, New ItemReadyForQueueEventArgs(oItem)) 
    End If 
    RaiseEvent ItemReadyForQueue(Me, New ItemReadyForQueueEventArgs(oItem)) 
End Sub 
Public Class ItemReadyForQueueEventArgs 
    Inherits System.EventArgs 
    Private _ReportTemplate As h3Budgeteer.FileSystem.ReportTemplateFile.ReportTemplate = Nothing 
    Public ReadOnly Property ReportTemplate() As h3Budgeteer.FileSystem.ReportTemplateFile.ReportTemplate 
     Get 
      Return _ReportTemplate 
     End Get 
    End Property 
    Public Sub New(ByVal oReportTemplate As h3Budgeteer.FileSystem.ReportTemplateFile.ReportTemplate) 
     _ReportTemplate = oReportTemplate 
    End Sub 
End Class 

끝 지역

+0

이 경우의 "위임"은 기본적으로 자체 양조 이벤트입니다. 나는 그것을 제거 할 것이다. –

답변

4

전 대리인을 완전히 완전히 삭제한다고 말합니다.

대리인이 이벤트와 똑같은 일을하고 있습니다. 프레임 워크의 Event 호출 대신에 여러분 자신의 이벤트 배관을 작성하고 있습니다. 이벤트는 사용하는 것이 더 쉽다는 점을 제외하고는 작성한 내용과 거의 동일합니다. 또한 이벤트로부터 더 쉽게 구독을 취소 할 수 있습니다.

두 가지를 모두 제공하는 이점은 없습니다. 이벤트는 "위임자"가하는 모든 일을 처리하며 훨씬 명확합니다.

(당신은 클래스 라이브러리로이를 개발하는 경우 이전 :

, 나는 당신의 클래스가 봉인되지 만들고, 그리고 더 많은 표준 접근 방식을 다음과 같은 제안했다. 논리를 재정의하거나 코드에 삽입하고 이벤트를 허용하는 일반적인 접근 방식은 서브 클래 싱을위한 후크를 제공하는 것입니다.

대리인은 사용자가 자신의 논리를 연결할 수 있도록 이와 같은 상황에서 사용될 수 있습니다. 그러나 대부분의 경우 가상 기능을 보호하면이를 더 명확하게 처리 할 수 ​​있습니다.

이벤트는 정확히 "이벤트"를 사용자에게 알리는 이벤트입니다. 사용자가 대리인을 연결하는 고리이어야합니다.

예를 들어 대리자 및 이벤트를 제공하는 대신 기본 Windows Forms 컨트롤은 보호 된 메서드 (예 : OnMouseDown)와 기본적으로 트리거되는 이벤트 (MouseDown)를 사용합니다.

사용자가 클래스를 서브 클래스 화하고 로직을 재정의 할 수 있습니다 (위임자가 필요한 이유 일 수 있습니다). 또한 이벤트를 처리 할 수 ​​있습니다.

내가 대리자를 제공 할 곳은 드문 경우이지만 클래스 나 메서드에서 사용자가 논리를 추가해야하는 경우입니다. 이 경우 추상 기본 클래스를 제공하거나 해당 논리에 전달 된 대리자를 가질 수 있습니다. 좋은 예가 LINQ의 .Where() 메서드입니다. 필터링에 사용되는 술어가 없으면 쓸모가 없으므로 위임자를 전달하는 것이이 경우에 적합합니다. 그러나 이와 관련된 이벤트는 없습니다. 실제로 다른 기능을 제공합니다.

+0

아마이 클래스가 별도의 스레드에서 "작업"을 수행한다고 추가해야합니다. 차이가 있습니까? 어떻게 생각합니까? – hmcclungiii

+0

아니요 - 차이는 없습니다. 사실, 서브 클래 싱을 사용하는 것이 더 중요하다고 생각합니다. 대리인이 전달하도록 허용하면 실수로 크로스 스레드 동기화 문제가 열리게됩니다. –

+0

다른 스레드의 대리자를 익명 메서드로 전달하면 다른 스레드에서 상태를 쉽게 전달할 수 있습니다. 이 경우 사용자는 잠재적으로 크로스 스레드 문제를 일으킬 수 있음을 인식하지 못합니다. 하위 클래 싱은보다 명확하고이 경우 문서화하기 쉽습니다. –

0

클래스 라이브러리에 필요한 것은 공용 이벤트 행 코드를 작성하는 것입니다.

Public Event TimerElapsed(ByVal sender As Object, ByVal e As System.EventArgs) 

물론 라이브러리의 어느 곳에서나 이벤트를 발생 시키십시오. 모든 클라이언트 개발자는 이벤트에 핸들러를 추가합니다.

라이브러리가 해당 클래스의 이벤트를 처리하지 않는 한 중복되지 않습니다.

+0

Public 이벤트 선언을하는 것만으로도 문제는 내 개체의 이벤트를 처리하는 모든 개체가 내 개체에 대한 참조를 필요로한다는 것입니다. 왜 그렇게 긴밀하게 결합되어야하는지 모르겠다. – hmcclungiii

+0

위임자와 함께 "처리"하는 모든 객체는 동일한 문제가 있습니다. 이벤트는 대리자 호출 일뿐입니다. 차이점은 이벤트에 대한 응답으로 사용자에게 위임자를 호출한다는 것입니다. 이벤트에 응답 할 수있는 기능을 추가하려면 이벤트를 사용하십시오. –

0

generic EventHandler을 사용하여 위임자를 제거 할 수 있습니다. EventArgs에서 상속받은 클래스를 직접 작성하면됩니다.

Public Class Foo 
    Inherits EventArgs 
End Class 

Public Class Bar 
    Public Event MyEvent As EventHandler(Of Foo) 
End Class 

필자는 중복되는 것으로 생각하지 않습니다. this 질문에 대한 첫 번째 답변을 참조하십시오. 빈 이벤트 핸들러를 추가하면 이벤트를 수신/처리하고 싶지 않을 때 이벤트가 발생하면 NullReferenceException이 발생하지 않습니다.

-EDIT-

코드를 본 후, 나는 Reed에 동의합니다. 공유 라이브러리가 될 것이므로 소비자의 이벤트 처리기를 실행해야한다고 생각하지 않습니다. 도서관의 일은 사건을 해고하고 소비자에게 무슨 일이 있었는지 알려주는 것입니다. 이벤트를 처리하거나 처리하지 못하게하는 것은 그들에게 달려 있습니다.

귀하의 속성이 중복되었다고 말할 수 있습니다. 본질적으로 이벤트 핸들러입니다.

+0

그러나 비슷한 위임자는 System.EventArgs에서 상속 한이 방법을 사용하고 있습니다.이 방법은 이벤트와 대리자 모두 매개 변수로 사용해야하므로 실제로 문제를 해결하지는 못합니다. 그래도 고마워! – hmcclungiii