C# 如何使仅最远的子级接收共享事件?

C# 如何使仅最远的子级接收共享事件?,c#,events,C#,Events,我的代码遇到了一些设计问题。 我有一个创建子对象的对象(子对象可以创建另一个子对象,等等),两个对象都订阅同一事件。 但是,我只希望最子对象接收事件 我的项目概述: 我正在创建一个IVR系统。当用户呼叫系统时,用户将有X个菜单选项。根据用户的选择,他们将有一个子菜单的选择,等等。我正在为此使用状态机。每个状态机都需要“监听”用户何时在手机上按某个号码。但只有当前状态机需要处理输入的数字。每个状态机都可以创建一个新的状态机来表示子菜单 以下是一些示例代码: 基类: public delegate

我的代码遇到了一些设计问题。 我有一个创建子对象的对象(子对象可以创建另一个子对象,等等),两个对象都订阅同一事件。 但是,我只希望最子对象接收事件

我的项目概述: 我正在创建一个IVR系统。当用户呼叫系统时,用户将有X个菜单选项。根据用户的选择,他们将有一个子菜单的选择,等等。我正在为此使用状态机。每个状态机都需要“监听”用户何时在手机上按某个号码。但只有当前状态机需要处理输入的数字。每个状态机都可以创建一个新的状态机来表示子菜单

以下是一些示例代码:

基类:

public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
    public event DoSomething myEvent;
    private IObject foo;

    public Base ()
    {
        foo = new myObjectA(this);
    }

    public void SomeAction()
    {
        ((myObjectA)foo).CreateChild();
    }

    public void EventFired()
    {
        if (myEvent != null)
        {
            myEvent(this, new EventArgs());
        }
    }
}
反对意见a:

class myObjectA : IObject
{
    private Base theCallingObject;
    private IObject child;
    public myObjectA (Base _base)
    {
        theCallingObject = _base;
        theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
    }

    public void CreateChild()
    {
        child = new myObjectB(theCallingObject);
    }

    void theCallingObject_myEvent(object sender, EventArgs data)
    {
        // Handle event
        MessageBox.Show("myObjectA");
    }
}
反对意见b:

class myObjectB : IObject
{
    private Base theCallingObject;
    public myObjectB (Base _base)
    {
        theCallingObject = _base;
        theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
    }

    void theCallingObject_myEvent(object sender, EventArgs data)
    {
        // Handle event
        MessageBox.Show("myObjectB");
    }
}
现在当我这样做的时候:

Base blah = new Base();
blah.SomeAction();
blah.EventFired();
我得到A和B的消息框。 我需要实现Base,这样只有myObjectB才能获得事件。 我将有数百个myObject,因此我需要在基础级别而不是myObject级别实现。另外,如果有数百个对象,在myObject级别处理它仍然需要触发事件,从而导致性能问题

我考虑过的一个解决方案是,当myObjectA创建子对象时,取消订阅该事件,然后在返回myObjectA级别时重新订阅。不过,我觉得还有更好的办法

有人有什么想法吗

编辑:使用payo的输入,我得出以下结论:

public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
    private IObject foo;
    private List<DoSomething> _myEventStorage;

    public event DoSomething myEvent
    {
        add
        {
            _myEventStorage.Insert(0, value);
        }
        remove
        {
            _myEventStorage.Remove(value);
        }
    }

    public Base ()
    {
        _myEventStorage = new List<DoSomething>();
        foo = new myObjectA(this);
    }

    public void SomeAction()
    {
        ((myObjectA)foo).CreateChild();
    }

    public void EventFired()
    {
        _myEventStorage[0].Invoke(this, new EventArgs());
    }
}
public委托void DoSomething(对象发送方、事件参数数据);
公共阶级基础
{
私人对象foo;
私人清单(我的档案库);;
公共事件DoSomething myEvent
{
添加
{
_myEventStorage.Insert(0,值);
}
去除
{
_myEventStorage.Remove(值);
}
}
公共基地()
{
_myEventStorage=新列表();
foo=新的肌体(本);
}
公共行动
{
((myObjectA)foo.CreateChild();
}
public void EventFired()
{
_myEventStorage[0]。调用(这是新的EventArgs());
}
}

您需要显式实现myEvent(添加/删除)处理程序,并独立于注册的观察者跟踪“最远的”。然后您可以将通知发送到单个实例。

对于事件,每个订阅者都排队(放在列表的末尾),这是一个FIFO模型。您希望最子对象“拥有”事件,而不仅仅是订阅和成为其他未知对象的抽象列表的一部分

我将提供一个新的模型来代表您正在尝试做的事情。这可能是Jason的建议:(我打字时他发布了他的答案)

这只会持续一段时间。另一个选项(添加到此自定义添加/删除)是提供派生的EventArgs:

public class ChainEventArgs : EventArgs
{
  public bool Handled { get; set; }
}
public delegate void DoSomething(object sender, ChainEventArgs data);

...

  public event DoSomething myEvent
  {
    add
    {
      var temp = _myEventStorage;
      _myEventStorage = null;
      _myEventStorage += value;
      _myEventStorage += temp; // now all are called, but FILO
    }
    remove
    {
      _myEventStorage -= value;
    }
  }
此时,您可以在每个IOObject上检查
Handled

void theCallingObject_myEvent(object sender, ChainEventArgs data)
{
  if (data.Handled)
    return;

  if (I_want_to_block_parents)
    data.Handled = true;
  // else leave it false
}
或者,给基类增加一些复杂性,并停止调用链(让孩子们无需检查
Handled
)。我将用一个委托列表显示解决方案,但是一些MulticaseDelegate强制转换和调用也可以这样做。我只是觉得列表代码可能更具可读性/可维护性

public class Base
{
  private List<DoSomething> _myEventStorage;
  public event DoSomething myEvent
  {
    add
    {
      _myEventStorage.Insert(0, value);
    }
    remove
    {
      _myEventStorage.Remove(value);
    }
  }
...
  public void EventFired()
  {
    var args = new ChainEventArgs();
    foreach (var handler in _myEventStorage)
    {
      handler(this, args);
      if (args.Handled)
        break;
    }
  }
}
公共类基
{
私人清单(我的档案库);;
公共事件DoSomething myEvent
{
添加
{
_myEventStorage.Insert(0,值);
}
去除
{
_myEventStorage.Remove(值);
}
}
...
public void EventFired()
{
var args=new ChainEventArgs();
foreach(myEventStorage中的变量处理程序)
{
处理程序(this,args);
如果(参数已处理)
打破
}
}
}

你能不能用一个线程(或新的C#5异步程序)代替状态机来实现这一点,等待按下按钮?@Random832我真的不明白你想说什么。但是为每个调用单独设置一个调用是不可能的,因为在任何情况下都可能有多达100个调用处于活动状态,并且上下文切换将开始影响性能。
public class Base
{
  private List<DoSomething> _myEventStorage;
  public event DoSomething myEvent
  {
    add
    {
      _myEventStorage.Insert(0, value);
    }
    remove
    {
      _myEventStorage.Remove(value);
    }
  }
...
  public void EventFired()
  {
    var args = new ChainEventArgs();
    foreach (var handler in _myEventStorage)
    {
      handler(this, args);
      if (args.Handled)
        break;
    }
  }
}