在类构造函数中引发事件时的空对象引用

时间:2014-03-27 08:03:17

标签: c# events exception

我在这里遇到一些问题,我正在使用一个名为Cell的课程,当我创建每个单元格时,我想要引发一个OnCellCreated附加的事件IGameViewer最终。由于一些奇怪的原因,它不起作用,现在我绕过了这个而不是在构造函数中调用IGameViewer.DisplayCell,但它非常奇怪,因为它从构造函数传递完全相同的对象引用并且它可以工作,但是当我试着用我的事件来做我将得到一个空对象引用。那么有人有任何想法吗?

这是代码

class Cell
{
    public delegate void CellChangedHandler(Cell cell);

    #region Properties & Fields

    private Mark markType = Mark.Empty; 
    private IGameViewer viewer;
    public static event CellChangedHandler OnCellChanged; 
    public static event CellChangedHandler OnCellCreated;
    public readonly Tuple<int, int> pos;
    public Mark MarkType { 
        get { return markType; } 
        set 
        {
            // Only allow changes to cells without a mark 
            if (markType.Equals(Mark.Empty)) 
            {    
                markType = value;
                OnCellChanged(this); //Model -> Viewer & Presenter, both can attach to this event
            }      
        } 
    }

    #endregion

    #region Constructors

    public Cell(IGameViewer viewer, Tuple<int, int> coords)
    {
        this.viewer = viewer;
        this.pos = coords;
        OnCellCreated(this); // <- This causes an object null reference exception to be thrown
        viewer.DisplayCell(this); // <- This doesn't, even if I reverse the calling order
    }

    #endregion

}

3 个答案:

答案 0 :(得分:3)

您的OnCellCreated事件为空,因为还没有订阅它。如果你已经在建设者中调用它,调用者如何做到这一点。 ? 如果尚未创建实例(您在构造函数中),则无法订阅实例事件

您可以创建CellFactory类并将CellCretaed事件添加到工厂。您要求CellFactory创建Cell实例,并在创建它之后CellFactory引发一个事件。当然,您必须在调用工厂方法之前订阅该事件。

答案 1 :(得分:1)

每当提出该事件时,检查该事件是否有订阅者

public Cell(IGameViewer viewer, Tuple<int, int> coords) {
  this.viewer = viewer;
  ...

  if (!Object.ReferenceEquals(null, OnCellCreated))
    OnCellCreated(this); 
  ...
}

答案 2 :(得分:0)

正如@Tigran回答的那样,问题是还没有人订阅这个活动。通过在构造函数上调用事件,您期望发生什么?

如果您遵循该模式在.NET类中实现事件,那么这种情况从未发生过。

将您的代码更改为:

class Cell
{
    private Mark markType = Mark.Empty; 
    private IGameViewer viewer;
    public static event EventHandler CellChanged; 
    public readonly Tuple<int, int> pos;

    public Cell(IGameViewer viewer, Tuple<int, int> coords)
    {
        this.viewer = viewer;
        this.pos = coords;
        viewer.DisplayCell(this);
    }

    public Mark MarkType { 
        get { return markType; } 
        set 
        {
            // Only allow changes to cells without a mark 
            if (markType.Equals(Mark.Empty)) 
            {    
                markType = value;
                OnCellChanged();
            }      
        } 
    }

    protected virtual void OnCellChanged()
    {
        var handler = this.CellChanged;
        if (handler)
        {
            handler(this, EventArgs.Empty);
        }
    }
}