Подтвердить что ты не робот

Исключение NullReferenceException при запуске события

Рассмотрим следующее:

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());, и я не могу понять, почему. Все мои другие события увольняются очень хорошо, и я не понимаю, как это все по-другому.

Любые идеи?

4b9b3361

Ответ 1

Вам нужна нулевая проверка С#, вы не можете вызывать события, когда в этом событии нет обработчиков.

Нормальным было бы реализовать метод OnConnectFailed:

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

Кроме того, первым аргументом обработчика события должен быть this, а не исключение. Если вам нужно передать исключение в обработчик событий, создайте класс EventArgs со свойством исключения.

Кроме того, нет смысла в создании события из конструктора... ничто не может добавить к нему обработчик.

Ответ 2

Нашел,

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

Ответ 3

Также в С# 6 вы можете выполнить нулевую проверку следующим образом:

connectFailed?.Invoke(this, e); 

Ответ 4

'connectFailed' - это событие. Если никто не подозревает о событии, он будет пустым, поэтому вам нужно проверить нулевой случай.

Чтобы сделать это безопасным, вам понадобится нулевая проверка, например:

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

Однако, этого шаблона недостаточно, из-за многопоточности. Рекомендуемый подход:

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

Это не только проверяет нулевое условие, но и сначала копирует событие, чтобы гарантировать его потокобезопасность (если очередь событий изменяется одним потоком, в то время как событие обрабатывается в другом потоке, поведение может быть undefined. Сначала скопировав его, вы убедитесь, что список подписчиков остается неизменным в течение всего процесса обработки событий)