2008-11-17 65 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)); 
     } 
    } 
}