Использование делегатов и объявление событий - PullRequest
3 голосов
/ 20 марта 2009

Я разрабатываю библиотеку классов для использования другими разработчиками и позволю им либо объявить экземпляр моего класса, используя 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 и т. Д.,

Спасибо за любой совет по этому вопросу ... Я думаю, что я избыточен и не хочу бессмысленного кода, не говоря уже о том, чтобы избегать принципа СУХОЙ.

{edit} Просто хотел опубликовать оставшуюся часть кода и подчеркнуть, что «работа», выполняемая экземпляром этого класса, выполняется в отдельном потоке. {/ Edit}

#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

Конечная область

Ответы [ 3 ]

4 голосов
/ 20 марта 2009

Я бы сказал, просто полностью удалите своего делегата.

Ваш делегат делает то же самое, что и мероприятие. Вы в значительной степени пишете свой собственный метод обработки событий, а не используете вызов события фреймворка. Событие в значительной степени соответствует тому, что вы написали, за исключением того, что его проще использовать, а также легче отписаться от него.

Нет никакого преимущества в предоставлении обоих - событие делает все, что делает ваш «делегат», и гораздо более понятно.

(Ранее:)

Если вы разрабатываете это как библиотеку классов, я бы предложил просто не запечатывать ваш класс и следовать более стандартному подходу. Обычный подход, позволяющий переопределять логику или вставлять ее в код, а также разрешать события, заключается в предоставлении хуков для подклассов.

Делегаты могут использоваться в такой ситуации, чтобы позволить пользователю подключить свою собственную логику. Однако во многих случаях наличие защищенных виртуальных функций делает это более понятным и намного легче выполнить.

События должны быть именно такими, событиями, которые уведомляют пользователя о каком-то «событии». Это должны быть хуки, когда пользователь присоединяет свой делегат.

Например, вместо предоставления делегатов и событий базовые элементы управления Windows Forms используют защищенный метод (например, OnMouseDown) и событие, которое вызывается по умолчанию (MouseDown).

Это позволяет пользователю создавать подклассы вашего класса и переопределять логику (возможно, именно поэтому вам нужны делегаты), а также обрабатывать событие.

Единственное место, где я предоставляю делегатов, - это редкие случаи, когда ваш класс или метод ТРЕБУЕТ логики для добавления пользователем. В этом случае вы можете либо предоставить абстрактный базовый класс, либо передать делегат для этой логики. Хорошим примером этого является метод .Where () в LINQ. Где бесполезно без предиката, используемого для фильтрации, поэтому передача делегата имеет смысл в этом случае. Обратите внимание, что с этим событием не связано ни одно событие - оно действительно предоставляет другую функцию.

0 голосов
/ 20 марта 2009

Вы можете избавиться от делегата, используя универсальный EventHandler . Все, что вам нужно сделать, это создать свой собственный класс, который наследуется от EventArgs.

Public Class Foo
    Inherits EventArgs
End Class

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

Я не думаю, что вы избыточны. См. Первый ответ на этот вопрос. Добавление пустого обработчика события гарантирует, что люди, использующие ваше событие, не получат исключение NullReferenceException при его запуске, если они не хотят слушать / обрабатывать событие.

-EDIT-

После просмотра вашего кода я согласен с Reed . Поскольку это будет разделяемая библиотека, я не думаю, что вам нужно будет выполнять обработчик событий потребителя. Работа вашей библиотеки - просто запустить событие и сообщить потребителю, что что-то случилось. Им решать, обрабатывать или не обрабатывать событие.

Я бы сказал, что ваши свойства избыточны. По сути, они являются обработчиками событий.

0 голосов
/ 20 марта 2009

Для вашей библиотеки классов все, что вам нужно, это написать публичную строку кода Event.

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

Не забудьте поднять событие в любом месте вашей библиотеки, конечно. Любой клиент-разработчик может добавить обработчик к событию.

Это не избыточно, просто не нужно, если ваша библиотека не будет обрабатывать какие-либо события из этого класса.

...