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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/531438/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 07:02:09  来源:igfitidea点击:

C#: Triggering an Event when an object is added to a Queue

c#eventsdelegatesqueue

提问by Andreas Grech

I need to be able to trigger a event whenever an object is added to a Queue<Delegate>.

每当将对象添加到Queue<Delegate>.

I created a new class that extends Queue:

我创建了一个扩展的新类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);
        }
    }
}

And then attached the event from another class, like such:

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

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

But whenever I enqueue an object (eventQueue.Enqueue(something)), the attached event is not being fired.

但是每当我将一个对象 ( eventQueue.Enqueue(something)) 加入队列时,附加的事件就不会被触发。

What am I missing here?

我在这里缺少什么?

采纳答案by Marc Gravell

If you mean the non-generic Queueclass, then you can just override Enqueue:

如果您的意思是非泛型Queue类,那么您可以覆盖Enqueue

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

However, if you mean the generic Queue<T>class, then note that there is no suitable virtual method to override. You might do better to encapsulatethe queue with your own class:

但是,如果您指的是泛型Queue<T>类,请注意没有合适的虚方法可以覆盖。用自己的类封装队列可能会更好:

(** important edit: removed base-class!!! **)

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

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

However, looking at your code, it seems possible that you are using multiple threads here. If that is the case, consider a threaded queueinstead.

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

回答by Krzysztof Kozmic

You have to override Enqueue, to call OnChanged.

您必须覆盖 Enqueue,才能调用 OnChanged。

回答by Konstantin Savelev

try

尝试

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

回答by NovaJoe

I just did write up on what I call a TriggeredQueue. It's inspired the answer by Marc Gravell.

我只是写了一个我称之为 TriggeredQueue 的东西。它的灵感来自 Marc Gravell 的答案。

You can find my post here: http://joesauve.com/triggeredqueuet

你可以在这里找到我的帖子:http: //joesauve.com/triggeredqueuet

And the Gist here: http://gist.github.com/jsauve/b2e8496172fdabd370c4

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

It has four events:

它有四个事件:

  • WillEnqueue
  • WillDequeue
  • DidEnqueue
  • DidDequeue
  • 将入队
  • 出队
  • 入队
  • 出队

You can hook into any of these like so:

你可以像这样挂钩任何一个:

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

One neat trick is that you can use the DidDequeue method to kick off some process to ensure that the queue is full by making a web request or loading some data from a filesystem, etc. I use this class in Xamarin mobile apps to ensure that data and images are pre-cached in order to provide a smooth user experience, instead of loading images AFTER they scroll onto the screen (like you might see in Facebook and countless other apps).

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