0

事实证明这是一个很长的问题,所以提前感谢所有放弃时间阅读并评论/回答的人:)


编辑

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


我正在使用通过接口实现的观察者模式:

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时,对象将简单地向控制台窗口输出一个字符串。NotifyMySubject

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

我遇到的问题是取消订阅过程不起作用

我真的不明白为什么。


问题

  • 为什么取消订阅过程不起作用?
  • 比较 2 个事件处理程序时会发生什么?它们如何定义为相等或不相等?这可能会导致为什么调用列表Contains方法总是返回的答案false
4

1 回答 1

1

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.

于 2011-09-15T17:57:39.887 回答