Почему при попытке отписаться от события объект обработчика событий не распознается? - PullRequest
0 голосов
/ 15 сентября 2011

Этот вопрос оказался довольно длинным, поэтому заранее благодарю всех, кто посвятил свое время его чтению и комментарию / ответу:)


Изменения

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


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

public interface IObserver<in T>where T:EventArgs
{
    void Update(object sender, T e);
}

public interface ISubject<in T, TU>where TU:EventArgs
{
    event EventHandler<TU> Notify;

    T State { set; }

    void Attach(Action<object,TU> callback);
    void Detach(Action<object, TU> callback);
}


Я создал два простых класса, которые реализуют эти интерфейсы. Объект MyObserver просто выведет строку вокно консоли при возникновении события Notify в объекте MySubject.

    public class MyObserver:IObserver<TestEventArgs>
    {
        private ISubject<bool, TestEventArgs> _subject;

        public MyObserver(ISubject<bool, TestEventArgs> subject)
        {
            _subject = subject;
        }

        public void Subscribe()
        {
            _subject.Attach(Update);
        }

        public void Unsubscribe()
        {
            _subject.Detach(Update);
        }

        public void Update(object sender, TestEventArgs e)
        {
            Console.WriteLine(e.TestMessage);
        }
    }

    public class MySubject:ISubject<bool, TestEventArgs>
    {
        public void ObservableEvent(string message)
        {
            InvokeNotify(message);
        }

        private void InvokeNotify(string message)
        {
            EventHandler<TestEventArgs> handler = Notify;

            if(handler != null)
            {
                handler(this, new TestEventArgs(message));
            }
        }

        public event EventHandler<TestEventArgs> Notify;

        public bool State
        {
            set { throw new NotImplementedException(); }
        }

        public void Attach(Action<object, TestEventArgs> callback)
        {
            Notify += new EventHandler<TestEventArgs>(callback);
        }

        public void Detach(Action<object, TestEventArgs> callback)
        {
            Notify -= new EventHandler<TestEventArgs>(callback);
        }
    }

    public class TestEventArgs:EventArgs
    {
        public TestEventArgs(string message)
        {
            TestMessage = message;
        }

        public string TestMessage { get; private set; }
    }


Эта тестовая программа показывает, что:

  • до того, как myObserver подписался на событие, в окно консоли не выводится сообщение.
  • после того, как myObserver подписался на событие Notify, сообщение выводится в окно консоли.
  • после того, как myObserver отписался от события Notify на сообщение все еще выводится в окно консоли

    static void Main(string[] args)
    {
        MySubject mySubject = new MySubject();
        MyObserver myObserver = new MyObserver(mySubject);
    
        //we have not subscribed to the event so this should not be output to the console
        mySubject.ObservableEvent("First Test");
    
        myObserver.Subscribe();
    
        //we are now subscribing to the event. This should be displayed on the console window
        mySubject.ObservableEvent("Second Test");
    
        myObserver.Unsubscribe();
    
        //We have unsubscribed from the event. I would not expect this to be displayed
        //...but it is!
        mySubject.ObservableEvent("Third Test");
    
        Console.ReadLine();
    }
    

Проблема У меня возникло то, что процесс отмены не работает .

Я действительно не понимаю, почему.


Вопросы

  • Почему не работает процесс отписки?
  • Что происходит при сравнении двух обработчиков событий?Как они определяются как равные или нет?Это может привести к ответу на вопрос, почему метод списка вызовов Contains всегда возвращает false.

1 Ответ

1 голос
/ 15 сентября 2011

Я подозреваю, что ваша проблема в том, что этот код:

public void Attach(Action<object, TestEventArgs> callback)
{
    Notify += new EventHandler<TestEventArgs>(callback);
}

Фактически выделяет новый объект, как и соответствующий код Detach. Так что то, что отсоединяется, не то же самое, что и то, что прикрепляется.

Я не уверен, но вы можете исправить это, изменив Attach и Detach так, чтобы они:

void Attach(EventHandler<TU> callback);
void Detach(EventHandler<TU> callback);

А в коде клиента:

public void Attach(EventHandler<TestEventArgs> callback)
{
    Notify += callback;
}

public void Detach(EventHandler<TestEventArgs> callback)
{
    Notify -= callback;
}

На самом деле я не пытался скомпилировать это, но похоже, что оно должно работать.

Или, если компилятор может выполнить преобразование типа:

public void Attach(Action<object, TestEventArgs> callback)
{
    Notify += callback;
}

Может быть стоит выстрел.

...