开发者

Why, when attempting to unsubscribe from an event, is the event handler object not recognised?

开发者 https://www.devze.com 2023-04-05 06:12 出处:网络
This has turned out to be quite a lengthy question, so thank you in advance to all those who give up their time to read it and comment/answer :)

This has turned out to be quite a lengthy question, so thank you in advance to all those who give up their time to read it and comment/answer :)

Edits

  • This Question has been majorly simplified.
  • Example code is now a complete, simple program

I am using an observer pattern implemented through interfaces:

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);
}

I have created two simple classes which implement these interfaces The MyObserver object will simply output a string to the console window when a Notify event is raised in the MySubject object.

    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; }
    }

This test program shows that:

  • before myObserver has subscribed to the event no message is output to the Console window.
  • after myObserver has subscribed to the Notify event the message is output to the Console window.
  • after myObserver has UNsubscribed from the Notify event the message is still output to the Console window

    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();
    }
    

The issue I'm having is that the unsubscribe process is not working.

I really don't understand why.

Questions

  • Why is the unsubscribe process not working?
  • What happens when comparing 2 event handlers? How are they defined as equal or not? This may lead to an answer to why the invocation list Contains method always returns false.


I suspect your problem is that this code:

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

Actually allocates a new object, as does the corresponding Detach code. So what's being detached isn't the same thing as what's being attached.

I'm not sure, but you might be able to fix it by changing your Attach and Detach so that they're:

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

And in the client code:

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

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

I haven't actually tried to compile this, but it looks like it should work.

Or, if the compiler can do the type conversion:

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

Might be worth a shot.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号