Sono stato dappled in C # dopo essere venuto da diversi anni in PHP. Non trovo la lingua particolarmente difficile, sebbene ci siano molti più costrutti su cui abituarmi.
La mia domanda è di aiutarmi a cambiare il modo di pensare quando uso C #. Più specificamente, per aiutarmi a pensare a soluzioni in un linguaggio statico quando sono stato rovinato da uno dinamico.
Per il mio esperimento ho creato una semplice copia di EventSispatcher di Symfony, che viene utilizzata in questo modo:
// PHP
class Sample
{
public function __construct()
{
$dispatcher = new EventDispatcher();
$dispatcher->addListener("sample.event", array($this, "onEvent"));
$dispatcher->dispatch ("sample.event", new Event());
}
public function onEvent(Event $event)
{
echo "Event Dispatched";
}
}
E questa è la mia replica in C # di EventDispatcher:
// C#
public delegate void EventListener (EventArgs args);
public class EventDispatcher
{
protected Dictionary<string, EventListener> Listeners = new Dictionary<string, EventListener> ();
public void AddListener (string eventName, EventListener listener)
{
EventListener l;
Listeners.TryGetValue (eventName, out l);
if (null == l) {
l = listener;
Listeners.Add (eventName, l);
} else {
l += listener;
}
}
public void Dispatch(string eventName, EventArgs args)
{
EventListener listener;
Listeners.TryGetValue (eventName, out listener);
if (null != listener) {
listener (args);
}
}
}
E finalmente questa è una copia dell'esempio PHP:
// C#
class Application
{
protected static EventDispatcher Dispatcher = new EventDispatcher();
public static void Main(string[] args)
{
Dispatcher.AddListener ("sample.event", onEvent);
Dispatcher.Dispatch ("sample.event", new ErrorEventArgs(new Exception()));
}
public static void onEvent(EventArgs args)
{
Console.Out.WriteLine ("Event Dispatched");
}
}
Ora la differenza è che sto inviando l'evento con ErrorEventArgs
, una classe figlia di EventArgs
. Questo va bene perché l'istanza è sostituita.
Tuttavia, in PHP posso dichiarare il listener come questo per accertarmi che l'evento corretto sia dato al metodo:
// PHP
public function onEvent(ErrorEvent $event)
{
echo "Event Dispatched";
}
Tuttavia lo stesso in C # non funzionerà:
// C#
public static void onEvent(ErrorEventArgs args)
{
Console.Out.WriteLine ("Event Dispatched");
}
Perché non corrisponde al delegato delegate void EventListener (EventArgs args)
.
Ora so che .NET ha già un sistema di eventi e sembra che sto reinventando la ruota, anche se hai familiarità con Symfony2 saprai che è un dispatcher di eventi non un tipico esempio di sé (gli eventi sono generalmente globalizzati) .
Potrei in questo caso definire solo i metodi per conformarsi con il delegato richiesto e usare l'introspezione per determinare se l'evento dovrebbe essere gestito. Oppure posso implementare AddListener
e Dispatch
come metodi generici, a costo di definire il dizionario come Dictionary<string, object>
.
Quindi la mia domanda si riduce a se mi sto avvicinando a questo nel modo sbagliato, se questo tipo di programmazione semi-dinamica è adatto, o c'è un modo veramente statico di implementarlo?
Tieni a mente che questo è un esperimento di esempio e nel mondo reale cercherò pratiche tradizionali per implementare questo specifico scenario.
EDIT:
Utilizzando la soluzione del dizionario di oggetti e generici, ecco il refactoring:
public delegate void EventListener<T> (T args);
public class EventDispatcher
{
protected Dictionary<string, object> Listeners = new Dictionary<string, object> ();
public void AddListener<T> (string eventName, EventListener<T> listener)
{
EventListener<T> l;
object obj;
if (Listeners.TryGetValue (eventName, out obj)) {
l = (EventListener<T>)obj; // handling required here if obj cannot be casted.
l += listener;
} else {
l = listener;
Listeners.Add (eventName, l);
}
}
public void Dispatch<T> (string eventName, T args)
{
EventListener<T> l;
object obj;
if (Listeners.TryGetValue (eventName, out obj)) {
l = (EventListener<T>)obj;
l (args);
}
}
}