C#:将对象添加到队列时触发事件

问题描述 投票:0回答:4

每当将对象添加到

Queue<Delegate>
时,我需要能够触发事件。

我创建了一个扩展的新类

Queue

public delegate void ChangedEventHandler(object sender, EventArgs e);

public class QueueWithChange<Delegate> : Queue<Delegate>
{
    public event ChangedEventHandler Changed;

    protected virtual void OnChanged(EventArgs e) {
        if (Changed != null)
        {
            Changed(this, e);
        }
    }
}

然后附加另一个类的事件,如下所示:

QueueWithChange<TimerDelegate> eventQueue = new QueueWithChange<TimerDelegate>();

//

eventQueue.Changed += new ChangedEventHandler(delegate(object s, EventArgs ex) {
    //This event is not being triggered, so this code is unreachable atm...and that is my problem

    if (eventQueue.Count > 0)
    {
        eventQueue.Dequeue().Invoke(new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(5) });
        actionTimer.Stop();
    }
});

但是每当我将一个对象放入队列(

eventQueue.Enqueue(something)
)时,附加的事件就不会被触发。

我在这里缺少什么?

c# events delegates queue
4个回答
38
投票

如果您指的是非泛型

Queue
类,那么您可以覆盖
Enqueue
:

public override void Enqueue(object obj)
{
    base.Enqueue(obj);
    OnChanged(EventArgs.Empty);
}

但是,如果您指的是通用

Queue<T>
类,请注意没有合适的虚拟方法可以重写。您可能会更好地使用自己的类来封装队列:

(**重要编辑:删除基类!!!**)

class Foo<T>
{
    private readonly Queue<T> queue = new Queue<T>();
    public event EventHandler Changed;
    protected virtual void OnChanged()
    {
        if (Changed != null) Changed(this, EventArgs.Empty);
    }
    public virtual void Enqueue(T item)
    {
        queue.Enqueue(item);
        OnChanged();
    }
    public int Count { get { return queue.Count; } }

    public virtual T Dequeue()
    {
        T item = queue.Dequeue();
        OnChanged();
        return item;        
    }
}

但是,查看您的代码,您似乎在这里使用了多个线程。如果是这种情况,请考虑使用线程队列


6
投票

我刚刚写了一篇关于我所说的 TriggeredQueue 的文章。这启发了 Marc Gravell 的回答。

您可以在这里找到我的帖子:https://joesauve.com/triggeredqueuelttgt

这里的要点:http://gist.github.com/jsauve/b2e8496172fdabd370c4

它有四个事件:

  • 将入队
  • 将出队
  • 入队了吗
  • 是否出队

您可以像这样连接到其中任何一个:

YourQueue.WillEnqueue += (sender, e) => {
    // kick off some process
};
YourQueue.DidEnqueue += (sender, e) => {
    // kick off some process
    // e.Item provides access to the enqueued item, if you like
};
YourQueue.WillDequeue += (sender, e) => {
    // kick off some process
};
YourQueue.DidDequeue += (sender, e) => {
    // kick off some process
    // e.Item provides access to the dequeued item, if you like
};

一个巧妙的技巧是,您可以使用 DidDequeue 方法来启动某些进程,以通过发出 Web 请求或从文件系统加载一些数据等来确保队列已满。我在 Xamarin 移动应用程序中使用此类来确保数据和图像被预先缓存,以提供流畅的用户体验,而不是在滚动到屏幕上后加载图像(就像您在 Facebook 和无数其他应用程序中看到的那样)。


1
投票

尝试

public new void Enqueue(Delegate d)
{
    base.Enqueue(d);
    OnChanged(EventArgs.Empty);
}

0
投票

您必须重写 Enqueue,才能调用 OnChanged。

© www.soinside.com 2019 - 2024. All rights reserved.