触发事件时NullReferenceException

时间:2011-04-23 21:12:39

标签: c# events sockets event-handling

请考虑以下事项:

class Client
{
    public static event EventHandler connectFailed;

    private Socket socket;

    public Client()
    {
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint endpoint = new IPEndpoint(
            IPAddress.Parse("192.168.1.100"),
            7900
            );

        try
        {
            socket.Connect(endpoint);
        }
        catch(Exception e)
        {
            connectFailed(e, new EventArgs());
        }
    }
}

假设其余代码已实现(Program.cs中的事件处理程序等)。

我在NullRefrerenceException行遇到了connectFailed(e, new EventArgs());的问题,我无法理解原因。我所有的其他事件都很好,但我不知道这有什么不同。

有什么想法吗?

4 个答案:

答案 0 :(得分:29)

您需要进行空检查 - 在C#中,如果没有在该事件上注册处理程序,则无法调用事件。

通常的做法是实现OnConnectFailed方法:

protected virtual void OnConnectFailed(e as EventArgs) {
    EventHandler tmp = connectFailed;
    if(tmp != null)
        tmp(this,e);
}

此外,事件处理程序的第一个参数应该是this,而不是例外。如果需要将异常传递给事件处理程序,请创建一个带有异常属性的EventArgs类。

此外,从构造函数中引发事件毫无意义......没有机会为其添加处理程序。

答案 1 :(得分:8)

同样在C#6中,你可以用这种方式进行 null检查

connectFailed?.Invoke(this, e); 

答案 2 :(得分:7)

找到它,

public delegate void OnRequestReceivedHandler(object sender);
public event OnRequestReceivedHandler ReqeustReceived = delegate { };

答案 3 :(得分:1)

'connectFailed'是一个事件。 如果没有人怀疑该事件,它将为null,因此您必须检查空案例。

为了确保安全,您需要进行空检查,即:

if (connectFailed != null)
    connectFailed(e, new EventArgs()); 

然而,由于多线程,这种模式还不够。推荐的方法是:

EventHandler temp = connectFailed;
if (temp != null)
    temp(e, new EventArgs()); 

这不仅会检查null条件,还会先复制事件以确保它是线程安全的(如果在另一个线程上处理事件时事件队列被一个线程更改,则行为可能是未定义的通过先复制它,确保用户列表在事件处理过程中保持不变)