为什么在尝试取消订阅事件时,事件处理程序对象无法识别?

时间:2011-09-15 12:52:03

标签: c# events .net-4.0 observer-pattern unsubscribe

这已经证明是一个非常冗长的问题,所以请提前感谢所有放弃阅读和评论/回答的人:)


编辑

  • 此问题已大大简化。
  • 示例代码现在是一个完整,简单的程序


使用通过接口实现的观察者模式

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事件后,该消息将输出到控制台窗口。
  • myObserverNotify事件取消订阅后,消息仍会输出到控制台窗口

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

问题我遇到的是取消订阅流程无效

我真的不明白为什么。


问题

  • 为什么取消订阅流程不起作用?
  • 比较2个事件处理程序会发生什么?他们如何被定义为平等或不平等?这可能会导致回答调用列表Contains方法始终返回false的原因。

1 个答案:

答案 0 :(得分:1)

我怀疑你的问题是这段代码:

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

实际上分配一个新对象,相应的Detach代码也是如此。所以分离的东西与所附的东西不同。

我不确定,但您可以通过更改AttachDetach来修复它,以便它们可以:

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

可能值得一试。