Вопрос о пользовательских событиях

Я делаю пользовательские события для C#, и иногда он не работает.

Это - то, как я заставляю событие произойти:

    private bool isDoorOpen;
    public bool IsDoorOpen {
        get { return isDoorOpen;}
        private set { isDoorOpen = value; DoorsChangeState(this, null);}
    }

И это объявления события:

    //events        
    public delegate void ChangedEventHandler(Elevator sender, EventArgs e);
    public event ChangedEventHandler PositionChanged;
    public event ChangedEventHandler DirectionChanged;
    public event ChangedEventHandler BreaksChangeState;
    public event ChangedEventHandler DoorsChangeState;

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

5
задан Malfist 7 May 2010 в 06:47
поделиться

5 ответов

Рекомендуемый способ вызова события -

var handler = this.DoorsChangeState;
if (handler != null)
    handler(this, null);

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

EDIT: Нашел статью, в которой говорится об условиях гонки. http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx

10
ответ дан 18 December 2019 в 13:11
поделиться

Я знаю, что этот вопрос обсуждался (и отвечал) несколько раз здесь, на SO.

Также где-то здесь у меня есть следующие методы расширения, чтобы упростить использование этого шаблона:

public static class EventHandlerExtensions
{
    public static void FireEvent<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs
    {
        var temp = handler;
        if (temp != null)
        {
            temp(sender, args);
        }
    }

    public static void FireEvent(this EventHandler handler, object sender)
    {
        var temp = handler;
        if (temp != null)
        {
            temp(sender, EventArgs.Empty);
        }
    }
}

Итак, в вашем коде вы можете сказать:

public bool IsDoorOpen
{
    get { return isDoorOpen;}
    private set
    {
        isDoorOpen = value;
        DoorsChangeState.FireEvent(this);
    }
}
4
ответ дан 18 December 2019 в 13:11
поделиться

Вам нужно проверить, было ли событие подписано.

Я использую эту стандартную форму для сброса всех моих событий.

var temp = EventName;
if(EventName!= null)
   temp(this, null);
0
ответ дан 18 December 2019 в 13:11
поделиться

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

Вы должны проверить:

if(DoorsChangeState != null)
{
   DoorsChangeState(this, null); // Only fire if subscribed to
}
0
ответ дан 18 December 2019 в 13:11
поделиться

Перед вызовом события вы должны проверить, не является ли событие нулевым:

if (DoorsChangeState != null)   
  DoorsChangeState(this, null);

Когда DoorsChangeState равно null, это означает, что нет слушателей этого события.

0
ответ дан 18 December 2019 в 13:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: