2008-11-17 20 views
3

Supposons que je souhaite créer un ensemble d'observateurs en fonction du type. C'est-à-dire, quand ils sont notifiés d'un événement, on leur dit le type de l'un des arguments et décide ensuite s'il faut agir sur la base s'il peut fonctionner sur ce type.C# Observateurs basés sur le type?

Existe-t-il des moyens simples de le faire? Je pensais que ce serait assez simple à faire avec les génériques, mais cela semble être plus difficile que je ne l'imaginais. Et je préférerais ne pas avoir à faire un tas de références à l'objet si je peux l'éviter.

Là où je suis coincé est en se faisant:

public delegate void NotifyDelegate<T>(IEnumerator<T> loadable, NotifyArgs na); 

interface IObserver 
{ 
    void Notify<T>(IEnumerator<T> loadable, NotifyArgs na); 
} 

class Subject 
{ 
    NotifyDelegate notifier; //won't compile: needs type args 

    void Register(IObserver o) 
    { 
     notifier += o.Notify; 
    } 
} 

Bien sûr, je pourrais faire le sujet générique aussi bien, mais je dois avoir un sujet distinct pour chaque type. Est-ce que quelqu'un a des conseils ici? Y a-t-il un élément de fonctionnalité qui me manque quelque part ou suis-je trop compliqué?

MISE À JOUR: J'ai trop simplifié les arguments que Notify et NotifyDelegate prennent. Au lieu de cela:

public delegate void NotifyDelegate<T>(NotifyArgs na); 

Je voulais vraiment faire quelque chose comme ceci:

public delegate void NotifyDelegate<T>(IEnumerator<T> loadable, NotifyArgs na); 

Ce que je suis fondamentalement essayer de passer avant et en arrière est une base de données à partir des données. Désolé si l'exemple de code précédent a dérouté quelqu'un.

Répondre

3

Tout d'abord, changer le code que vous avez obtenu les points suivants:

interface IObserver 
{ 
} 

class Subject 
{ 
    public Subject() 
    { 
    m_observers = new List<IObserver>(); 
    } 

    public void Register (IObserver o) 
    { 
    m_observers.Add (o); 
    } 

    List<IObserver> 
    m_observers; 
} 

Ensuite, la réflexion utiliser pour trouver une fonction appropriée en fonction du type de paramètre:

public void NotifyObservers (object param) 
    { 
    foreach (IObserver observer in m_observers) 
    { 
     foreach (MethodInfo method in observer.GetType().GetMethods (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance)) 
     { 
     if (method.Name == "Notify") 
     { 
      ParameterInfo [] 
      parameters = method.GetParameters(); 

      if (parameters.Length == 1 && parameters [0].ParameterType == param.GetType()) 
      { 
      method.Invoke (observer, new object [] { param }); 
      break; 
      } 
     } 
     } 
    } 
    } 

et l'utiliser comme ceci:

class Observer : IObserver 
{ 
    public Observer (Subject s) 
    { 
    s.Register (this); 
    } 

    void Notify (float value) 
    { 
    System.Diagnostics.Trace.WriteLine ("float value = " + value); 
    } 

    void Notify (int value) 
    { 
    System.Diagnostics.Trace.WriteLine ("int value = " + value); 
    } 
} 

static void Main (string [] args) 
{ 
    Subject 
    s = new Subject(); 

    Observer 
    o = new Observer (s); 

    float 
    v1 = 3.14f; 

    int 
    v2 = 42; 

    System.Diagnostics.Trace.WriteLine ("sending float"); 
    s.NotifyObservers (v1); 
    System.Diagnostics.Trace.WriteLine ("sending int"); 
    s.NotifyObservers (v2); 
} 
+0

idée intéressante . C'est un peu plus compliqué que ce que je veux implémenter, mais au moins, il semble que ça marchera si je ne peux pas trouver un moyen plus simple. –

2
interface IObserver 
{ 
    void Notify(NotifyArgs na); 
    bool SupportsType(Type t); 
} 

class Subject 
{ 
    List<IObserver> observers; 

    void Register(IObserver o) 
    { observers.Add(o); 
    } 

    void OnNotify(Type t, NotifyArgs args) 
    { 
     foreach (IObserver o in observers) 
     { 
     if (o.SupportsType(t)) o.Notify(args)); 
     } 
    } 
}