Ho intenzione di utilizzare questa interfaccia in un'architettura plug-in.
/// <summary>
/// Generic interface allowing you to react to an event.
/// You can block the event or just use it for notification.
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IEventObserver<in T> where T : class
{
/// <summary>
/// Throw an exception in here if you want to prevent the event firing.
/// </summary>
/// <param name="o"></param>
void CanFireEvent(T o);
/// <summary>
/// This is only called if no handler threw an event in the CanFire.
/// </summary>
/// <param name="o"></param>
void OnBeforeEvent(T o);
/// <summary>
/// This is called after the event has happened.
/// </summary>
/// <param name="o"></param>
void OnAfterEvent(T o);
}
Esempio di utilizzo:
public interface ISendMessageObserver : IEventObserver<SendMessageEventArgs>
{
}
Un plug-in può quindi implementare ISendMessageObserver
e impedire l'invio di messaggi generando un'eccezione nel metodo CanFireEvent
. Tuttavia, so che le eccezioni non dovrebbero essere usate per il normale controllo del flusso del programma, tuttavia è normale e ci si aspetta che i plugin interrompano il flusso. Sono andato per questo perché mi piacerebbe che il plugin fornisse un motivo per bloccare l'evento che può essere registrato o presentato all'utente.
Potrei cambiare CanFireEvent
in:
bool CanFireEvent(T o, ref message);
o
SomeTypeContainingAbortReason CanFireEvent(T o);
Ma entrambi non hanno nemmeno l'odore ideale.
Quindi cosa ne pensano le persone, eccezioni per il controllo del flusso OK in questa istanza?
Modifica
Ho separato CanFire
nella sua interfaccia e l'ho rinominato come PreviewEvent
.
/// <summary>
/// Generic interface allowing you to react to and block an event.
/// </summary>
/// <typeparam name="TArgs"></typeparam>
/// <typeparam name="TBlock"></typeparam>
public interface IEventPreviewer<in TArgs, out TBlock>
where TArgs : class
where TBlock : class, IEventBlock
{
/// <summary>
/// Return an IEventBlock to prevent the event from firing.
/// </summary>
/// <param name="args"></param>
TBlock PreviewEvent(TArgs args);
}
public interface IEventBlock
{
string BlockReason { get; }
}