【问题标题】:Why, when attempting to unsubscribe from an event, is the event handler object not recognised?为什么在尝试取消订阅事件时,无法识别事件处理程序对象?
【发布时间】:2011-11-17 20:54:58
【问题描述】:

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


编辑

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


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

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


我创建了两个实现这些接口的简单类 当MySubject 对象中引发Notify 事件时,MyObserver 对象将简单地向控制台窗口输出一个字符串。

    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 的答案。

【问题讨论】:

  • 嗯....NET 框架已经实现了观察者模式。你为什么要在这里做一个新的轮子?作业?
  • 这里有很多 代码。请尝试制作一个简短但完整的程序来演示问题,而不是所有周围的包袱。
  • @Brian:我想知道同样的事情并没有问它,因为我没有阅读整个问题并且可能错过了一些东西。无论如何,.NET 中的事件是观察者模式的实现,所以基本上,你 Lewray 使用观察者模式的一种实现来实现另一种?
  • @Brian - Fair Point,我想在有了这个想法之后,我对自己实现它有点忘乎所以,并没有考虑检查是否存在现有实现。我对 C# 和 .Net 并不完全陌生,但仍有很多东西要学! - 但是在查看 .NET IObservable...为什么有订阅方法,但没有取消订阅?
  • @Jon - 我知道,有很多包袱。我会看看我是否可以在更简单的环境中复制并将结果作为编辑或其他内容发布。

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


【解决方案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;
}

可能值得一试。

【讨论】:

  • 我已经解决了这个问题,它确实解决了问题!我想我对这个 article 表示您可以使用:+= new EventHandler(callback);+= callback; 感到困惑,但我想关键的区别在于,在他们的示例中,他们使用 EventHAndler 对象作为回调而不是 @ 987654332@。感谢您的帮助!
  • 只是为了完整性...最后一个建议没有建立,Action&lt;object, TestEventArgs&gt; 不能隐式转换为EventHandler&lt;TestEventArgs&gt;。再次感谢。
  • @Lewray:很高兴你成功了。并感谢关于最后一个建议的说明。我已经编辑了我的回复。
猜你喜欢
  • 2021-03-29
  • 1970-01-01
  • 2012-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多