事件处理引发InvalidOperationException - 寻找建议

时间:2014-05-06 14:05:33

标签: c# event-handling invalidoperationexception

我对这种方式的编程有点新意 - 有什么方法可以解决或建议使用事件和处理程序?

例如:

class objectA
{    
    public List<Handler> handlers;
    ...
    public onActionHappened
    {
        foreach(Handler h in handlers)
        {
            raiseEvent(this, eventArgs);
        }
    }

    ...
    public void DeleteThis()
    {
        handlers = null
    }
}

raiseEvent()将继续调用其他几个方法,其中一个方法将调用DeleteThis()。当一切都结束并且程序流返回到foreach循环的“}”的raiseEvent()时,它会发现处理程序已经被修改= null,因此抛出了InvalidOperationException的错误。

某些方法处理应该禁用此objectA作为功能的一部分 - 因此可能在某些时候由客户端代码调用Deletethis()。为了解决这个问题,我已经从List处理程序修改为只有一个Handler对象,但我觉得这应该是一种更好的解决方法。或者更好的编码方式。

有什么建议吗?提前谢谢!

3 个答案:

答案 0 :(得分:1)

如果在列表中使用ToArray,则创建其内容的副本,而不依赖于处理程序变量本身:

   foreach(Handler h in handlers.ToArray()
        {
            //optional break if you don't want the loop to continue after DeleteThis is called:  if(handlers==null)break;
            raiseEvent(this, eventArgs);
        }

答案 1 :(得分:0)

无法在定义事件的类之外触发事件。因此,如果您在A类之外移动处理程序,则不能再在A类中的处理程序中触发事件。

要解决此问题,请将处理程序放在另一个类中,比如说B类,并定义一个公共方法,该方法触发B类处理程序中的事件(在本例中为onActionHappened方法)。对于A类,只需调用B类的公共方法(onActionHappened)。

答案 2 :(得分:0)

解决问题的核心:解决问题的最直接方法是在枚举之前将列表分配给局部变量。

class objectA
{    
    public List<Handler> handlers;
    ...
    public void OnActionHappened()
    {
        List<Handler> lh = handlers;

        // TODO: Would probably make sense to check if lh is null here.

        foreach(Handler h in lh)
        {
            h.raiseEvent(this, eventArgs);
        }
    }
    ...
    public void DeleteThis()
    {
        handlers = null;
    }
}

实际上没有必要按照其他地方的建议创建列表副本。

由于你似乎是C#编程的新手,让我告诉你这里发生了什么。

List<T>是参考类型。我们假设你通过调用它的构造函数来创建一个新的List<T>

List<Handler> handlers = new List<Handler>();

现在,执行此语句会在计算机的内存中创建两件事:

  1. 列表对象本身。
  2. 引用列表对象的变量(“处理程序”)。
  3. enter image description here

    现在,如果计算机执行以下行:

    List<Handler> lh = handlers;
    

    我们最终会得到这样的结果:

    enter image description here

    最后,如果计算机执行以下行:

    handlers = null;
    

    情况如下:

    enter image description here

    正如您所看到的,这样我们通过本地列表变量“lh”维护对列表对象的有效引用,并将成员变量“handlers”设置为null不会再影响foreach枚举。