События в базовых классах
-
22-08-2019 - |
Вопрос
Хорошо, у меня есть базовый класс, который объявляет событие. StatusTextChanged
.Мой дочерний класс, конечно, не может напрямую вызвать это событие.
В итоге у меня получилось что-то вроде этого (для простоты):
Public MustInherit Class FooBase
Public Event StatusTextChanged(ByVal StatusText As String)
Protected Sub RaiseStatusTextChangedEvent(ByVal StatusText As String)
RaiseEvent StatusTextChanged(StatusText)
End Sub
End Class
И затем в дочернем классе я звонюMyBase.RaiseStatusTextChangedEvent("something")
.Есть ли лучший или более рекомендуемый способ сделать это?
редактировать:VB.NET или C#, в любом случае они работают по сути одинаково.
редактировать:Итак, после ответов я занимаюсь этим в базовом классе, а затем просто устанавливаю свойство StatusText в дочернем классе...
Public Event StatusTextChanged(ByVal StatusText As String)
Private _StatusText As String = "Idle."
Public Property StatusText() As String
Get
Return _StatusText
End Get
Protected Set(ByVal value As String)
RaiseEvent StatusTextChanged(value)
End Set
End Property
Решение
Я бы сказал, что вы довольно близки к рекомендуемому способу (или, по крайней мере, к тому, который я бы рекомендовал).
Я бы внес несколько изменений в ваш код, если бы был выбор:
- Сделать статустекстизменед
Protected Overridable
- Оберните StatusText в собственный класс EventArgs.
- Измените объявление StatusTextChanged на
Public Event StatusTextChanged As EventHandler(Of YourCustomEventArgs)
Результирующий код:
Пользовательский класс eventargs:
Public Class TextEventArgs
Inherits EventArgs
Private _text As String
Public Sub New(ByVal text As String)
_text = text
End Sub
Public ReadOnly Property Text() As String
Get
Return _text
End Get
End Property
End Class
Реализация события в вашем базовом классе:
Public Event StatusTextChanged As EventHandler(Of TextEventArgs)
Protected Overridable Sub OnStatusTextChanged(ByVal e As TextEventArgs)
RaiseEvent StatusTextChanged(Me, e)
End Sub
... и, наконец, строка кода для вызова события;либо в базовом классе, либо в классе, который его наследует:
OnStatusTextChanged(New TextEventArgs("some text"))
Это будет больше соответствовать тому, как события разрабатываются в остальной части платформы .NET.
Другие советы
Если у вашего дочернего класса нет особой необходимости переопределить метод базового класса, я бы сказал, что вызов реализации базового класса является абсолютно лучшим решением.
Это практически стандартный способ вызова событий базового класса через производный для сценариев такого типа.
Однако это может немного измениться в зависимости от того, кто контролирует StatusText для иерархии.Если в FooBase есть конкретное поле поддержки StatusText, которое можно изменить только с помощью средств доступа, то я бы не позволил дочернему элементу контролировать возникновение события StatusTextChanged.Вместо этого я бы принудительно вызывал события в установщике свойства StatusText.Это дает родительскому классу больше контроля над соблюдением любых контрактов, которые он хочет, когда следует и когда не вызывать указанное событие.
Однако если StatusText является свойством, которое должно быть определено производным классом, я бы выбрал отображаемый вами маршрут.
Одним из вариантов, который вы могли бы иметь, является оберните свойство статуса в базовом классе, так что оно поднимает само событие в изменении (в C#, как не знаю VB и в настоящее время не имеет доступа к Visual Studio))
private string _status;
public string Status
{
get { return _status; }
protected set
{
if (_status == value) return;
_status = value;
StatusChanged(value);
}
}
Вот мой код для события с делегатом и параметром текста статуса
Public Event Status As StatusEventHandler Protected Overridable Sub OnStatus(ByVal e As StatusEventArgs) RaiseEvent Status(Me, e) End Sub Public Delegate Sub StatusEventHandler(ByVal sender As Object, _ ByVal e As StatusEventArgs) <System.Serializable()> _ Public Class StatusEventArgs Inherits System.EventArgs Public Sub New() End Sub Public Sub New(ByVal statusText As String) _StatusText = statusText End Sub ' Enter code here for event properties, etc. Private _StatusText As String = "" Public Property StatusText() As String Get Return _StatusText End Get Set(ByVal value As String) _StatusText = value End Set End Property End Class