2008-11-17 48 views
3

假设我想根据类型创建一组观察者。也就是说,当他们被通知一个事件时,他们被告知其中一个参数的类型,然后根据是否可以操作该类型来决定是否采取行动。基于类型的C#观察者?

有没有简单的方法可以做到这一点?我认为这对于泛型会很简单,但似乎要比我想象的要困难。如果我可以避免的话,我宁愿不必处理投射一堆对象的引用。

当我陷入在这样做:

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; 
    } 
} 

当然,我可以使主题一般为好,但我必须为每个类型都有一个单独主题。有没有人有任何建议吗?有什么功能可以让我在某个地方失踪,或者我是否过于复杂?

UPDATE:我没有简化Notify和NotifyDelegate的参数。取而代之的是:

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

实际上,我想要做这样的事情:

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

什么基本上,我试图通过来回数据库中的数据。对不起,如果以前的代码示例困惑任何人。

回答

3

首先,更改代码,你有以下几点:

interface IObserver 
{ 
} 

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

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

    List<IObserver> 
    m_observers; 
} 

然后,使用反射来查找基于参数类型适当的功能:

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; 
      } 
     } 
     } 
    } 
    } 

,并使用它像这样的:

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

有趣的想法。这比我想要实现的要复杂一点,但至少在我无法找出更简单的方法时,它看起来会起作用。 – 2008-11-17 16:24:01

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)); 
     } 
    } 
}