“转发事件时,委托给实例方法不能为'this'”

时间:2014-04-05 22:22:33

标签: c# events handler

我正试图将班级OnClientMessage上的Client个活动转发到班级Server以外的我的图书馆。

Client.cs

public class Client
{
    private TcpClient tcpClient;
    private StreamWriter writer;
    private Boolean alive = true;
    private int id;

    public delegate void OnClientMessageHandler(Client sender, String message);
    public delegate void OnClientDisconnectHandler(Client sender);

    public event OnClientMessageHandler OnClientMessage;
    public event OnClientDisconnectHandler OnClientDisconnect;

    public Client(TcpClient tcpClient, int id)
    {
        this.tcpClient = tcpClient;
        this.id = id;

        writer = new StreamWriter(tcpClient.GetStream());

        new Thread(() =>
        {
            Listen(new StreamReader(tcpClient.GetStream()));
        }).Start();
    }

    void Listen(StreamReader reader)
    {
        while (tcpClient.GetStream().DataAvailable && alive)
        {
           OnClientMessage(this, reader.ReadLine());
           Thread.Sleep(150);
        }
    }

    public void Write(String message)
    {
        writer.WriteLine(message);
        writer.Flush();
    }

    public int GetID()
    {
        return id;
    }

    public void Close()
    {
        alive = false;
        writer.Close();
        tcpClient.Close();
        OnClientDisconnect(this);
    }
}

Server.cs

public class Server
{
    private IPAddress serverIP;
    private short serverPort;

    private TcpListener serverListener;
    private int serverClientCount;
    public List<Client> serverClients = new List<Client>();

    private Boolean running;

    public delegate void OnClientMessageHandler(Client sender, String message);
    public delegate void OnClientDisconnectHandler(Client sender);

    public event OnClientMessageHandler OnClientMessage;
    public event OnClientDisconnectHandler OnClientDisconnect;

    public Server(IPAddress ip, short port, Boolean autoStart = true)
    {
        this.serverIP = ip;
        this.serverPort = port;

        if(autoStart)
            OpenServer();
    }

    public void OpenServer()
    {
        serverListener = new TcpListener(serverIP, serverPort);
        serverListener.Start();
        running = true;

        while (running)
        {
            if (serverListener.Pending())
            {
                TcpClient tcpClient = serverListener.AcceptTcpClient();
                new Thread(() =>
                {
                    Client client;
                    client = new Client(tcpClient, serverClientCount);

                    client.OnClientMessage += new Client.OnClientMessageHandler(OnClientMessage);
                    client.OnClientDisconnect += new Client.OnClientDisconnectHandler(OnClientDisconnect);

                    serverClients.Add(client);
                    serverClientCount++;
                }).Start();
            }
            else
            {
                Thread.Sleep(150);
            }
        }
    }

    public void WriteToClient(Client client, String message)
    {
        client.Write(message);
    }

    public void WriteToAll(String message)
    {
        serverClients.ForEach(client => client.Write(message));
    }

    public void Shutdown()
    {
        running = false;
        serverClients.ForEach(client => client.Close());
        serverListener.Stop();
    }
}

现在,当事件发生时,应用程序崩溃Delegate to an instance method cannot have null 'this' 我做错了什么或者这不是转发活动的正确方法吗?

1 个答案:

答案 0 :(得分:6)

这是非常独特的,从来没有见过任何人这样做。它是.NET Framework中的一个回归,3.5为您提供了一个更好的例外。基本问题是您自己订阅了事件。一个简单的版本来重现崩溃:

using System;

class Program {
    public static event Action Kaboom;
    static void Main(string[] args) {
        Kaboom += new Action(Kaboom);    // 3.5 raises an exception here
        var handler = Kaboom;
        if (handler != null) handler();  // kaboom
    }
}

你实际上并没有“转发”这个事件。解开你的名字和代码。比方说,添加一个Fire()方法。