3

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

有什么简单的方法可以做到这一点吗?我认为这对泛型来说相当简单,但这似乎比我想象的要难。如果可以避免的话,我宁愿不必处理对对象的一堆引用。

我陷入困境的地方是这样做:

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

当然,我也可以将 Subject 设为通用,但是我必须为每种类型设置一个单独的 Subject。有人在这里有什么建议吗?是否有一些我在某处遗漏的功能,或者我是否过于复杂?

更新:我确实过度简化了 Notify 和 NotifyDelegate 采用的论点。而不是这个:

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

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

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

我基本上试图来回传递的是来自数据库的数据。抱歉,如果前面的代码示例让任何人感到困惑。

4

2 回答 2

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);
}
于 2008-11-17T16:11:35.867 回答
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));
      }
    }
}
于 2008-11-17T19:00:35.153 回答