События C #, что с этим нулем? - PullRequest
4 голосов
/ 28 января 2011

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

Скажите, у меня есть этот код.

    class ballClass
{


    public event EventHandler BallInPlay;


    public void onHit()
    {
        if (BallInPlay != null)
        {
            BallInPlay(this, new EventArgs());
        }
        else
        {
            MessageBox.Show("null!");
        }
    }



}

и я хочу поднять BallInPlayдаже когда метод onHit () запущен.

прямо сейчас он показывает мне, что BallInPlay IS нулевой.как или чем я должен "заполнить" его, чтобы он работал?

Спасибо!

Ответы [ 7 ]

9 голосов
/ 28 января 2011

Дело в том, что если для прослушивания этого события зарегистрировано ноль слушателей, событие будет нулевым. Если один или несколько слушателей зарегистрированы, он будет иметь значение.

Это означает, что если зарегистрировано ноль слушателей, и вы пытаетесь вызвать событие, не выполняя нулевую проверку, ваша программа выдаст исключение.

7 голосов
/ 28 января 2011

Вам необходимо подписаться на событие с помощью обработчика.Например:

BallClass ball = new BallClass();
ball.BallInPlay += BallInPlayHandler;
// Now when ball.OnHit is called for whatever reason, BallInPlayHandler
// will get called
...
private void BallInPlayHandler(Object sender, EventArgs e)
{
    // React to the event here
}

Для получения дополнительной информации вы можете прочитать мою статью о событиях и делегатах .

Обратите внимание, что я исправил регистр BallClass и OnHit выше - это хорошая идея использовать стандартные соглашения об именах .NET, чтобы ваш код лучше подходил к коду и делал его более читаемым для других.

Одна вещьна заметку: проверка на нуль, которую вы получили в данный момент, не является поточно-ориентированной.Последний подписчик мог отписаться после if, но до вызова.Потокобезопасная версия будет выглядеть следующим образом:

public void OnHit()
{
    EventHandler handler = BallInPlay;
    if (handler != null)
    {
        handler(this, new EventArgs());
    }
    else
    {
        MessageBox.Show("null!");
    }
}

Не гарантируется использование последних подписчиков (так как не задействован барьер памяти), но - это , гарантированно не выбрасывающийNullReferenceException из-за условий гонки.

2 голосов
/ 28 января 2011

Если для события не назначены обработчики событий, событие является нулевым. Думайте о событии как о Списке, когда в списке нет элементов, значение события становится null.

Попытка вызвать событие , когда ему не назначены обработчики событий, вызовет исключение NullReferenceException.

Нулевая проверка предотвращает исключение NullReferenceException.

Если вы хотите, чтобы BallInPlay работал, вам нужно добавить EventHandler.

Ваш код будет выглядеть примерно так:

BallInPlay += new EventHandler(YourFunctionNameGoesHere);

2 голосов
/ 28 января 2011

Нулевой тест имеет место, потому что, если NOONE НЕ СЛУШАЕТ событие, объект события, который вы вызвали, фактически является нулевым.Таким образом, без подписчиков вы получите исключение нулевого указателя.

1 голос
/ 28 января 2011
BallInPlay(this, new EventArgs());

Причина проверки null перед запуском события станет очевидной, как только вы поймете, что приведенная выше строка кода фактически скомпилирована, как если бы вы написали следующее:

BallInPlay.Invoke(this, new EventArgs());
//        ^^^^^^^

И, как мы все знаем, плохая идея вызывать метод для ссылки null. Вот почему вы должны сначала проверить это BallInPlay != null.


Дополнительные предложения:

  • Используйте EventArgs.Empty вместо new EventArgs().

  • Вы можете обойти чек на null, если вы инициализировали BallInPlay следующим образом:

    public event EventHandler BallInPlay= delegate { };

    Это работает, потому что теперь всегда есть «пустой» метод-обработчик, подписанный на это событие. Таким образом, у вас есть гарантия, что делегат события больше не будет null после инициализации. (Некоторые люди могут посчитать это немного неэффективным.)

    Вы всегда можете подписаться или отписаться от обработчиков событий с помощью операторов += или -= для события BallInPlay; например:

    ball.BallInPlay += (sender, e) => { /* react to the triggered event */ };

  • Я думаю ваш onHit (или, скорее, OnHit, если мы придерживаемся обычных соглашений, встречающихся в мире .NET) * Метод 1055 * не должен быть публичным , потому что это противостоит всей цели событий. События на самом деле являются делегатами, но с некоторыми дополнительными ограничениями. Одним из таких ограничений является то, что только класс, определяющий событие, может вызвать («вызвать») его. Делегаты, с другой стороны, могут быть вызваны кем угодно. Таким образом, если вы сделаете onHit общедоступным, тем самым позволяя кому-либо инициировать ваше событие, вы также можете определить BallInPlay в качестве делегата, то есть без ключевого слова event.

  • A поточно-ориентированная реализация вашего метода запуска событий onHit показана ниже. Обратите внимание, что внутри метода используется локальная копия делегата обработчика событий. Это сделано для того, чтобы убедиться, что обработчик событий не будет изменен (например, другим потоком) между проверкой null и вызовом.


protected virtual void OnHit()
{
    EventHandler handler = BallInPlay;  // use a local copy of the event
    if (handler != null)                // for better thread-safety!
    {
        handler(this, EventArgs.Empty);
    }
}
1 голос
/ 28 января 2011

Нулевой тест - определить, слушает ли что-либо событие или нет.Когда что-то присоединяется к обработчику события, BallInPlay больше не будет иметь значение null

0 голосов
/ 28 января 2011
BallInPlay += new EventHandler(myFunc);

public void myFunc(object sender, EventArgs e)
{
MessageBox.Show("Woho \o/");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...