С#: запуск события, когда объект добавляется в очередь

Мне нужно иметь возможность запускать событие всякий раз, когда объект добавляется к 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)), вложенное событие не запускается.

Что мне здесь не хватает?

Ответы

Ответ 1

Если вы имеете в виду не-общий 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;        
    }
}

Однако, глядя на ваш код, кажется, что вы используете несколько потоков здесь. Если это так, рассмотрите поточную очередь.

Ответ 2

Я только что написал о том, что я называю TriggeredQueue. Это вдохновило ответ Марка Гравелла.

Вы можете найти мой пост здесь: http://joesauve.com/triggeredqueuet

И суть здесь: http://gist.github.com/jsauve/b2e8496172fdabd370c4

Он имеет четыре события:

  • WillEnqueue
  • WillDequeue
  • DidEnqueue
  • DidDequeue

Вы можете подключить любое из них так:

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 для запуска некоторого процесса, чтобы убедиться, что очередь заполнена, сделав веб-запрос или загрузив некоторые данные из файловой системы и т.д. Я использую этот класс в мобильных приложениях Xamarin для убедитесь, что данные и изображения предварительно кэшированы, чтобы обеспечить плавный пользовательский интерфейс, вместо загрузки изображений ПОСЛЕ того, как они прокручиваются по экрану (как вы можете видеть в Facebook и бесчисленных других приложениях).

Ответ 3

попробовать

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

Ответ 4

Вам нужно переопределить Enqueue, чтобы вызвать OnChanged.