views:

1833

answers:

3

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

I created a new class that extends 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.

What am I missing here?

A: 

You have to override Enqueue, to call OnChanged.

Krzysztof Koźmic
Enqueue is not virtual on the generic Queue<T>
Marc Gravell
Right, that's a shame. I guess you'd have to create a IQueue interface and have your own implementation then.
Krzysztof Koźmic
+4  A: 

If you mean the non-generic Queue class, then you can just override 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 encapsulate the queue with your own class:

(** 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 queue instead.

Marc Gravell
Excellent; This is Exactly what I was looking for. Thanks Marc for the quality answer. And I will also check about the Threaded Queue you mentioned.
Andreas Grech
Note that I incorrectly set a base-class; fixed in the code...
Marc Gravell
From a design principle perspective it is better to use composition over inheritance (broadly speaking) so I support your solution.
uriDium
Marc, for what reason did you remove the base class ?
Andreas Grech
It was a mistake! I intended to use composition, not inheritance - since we've already observed that inheritance doesn't offer what we need...
Marc Gravell
A: 

try

public new void Enqueue(Delegate d)
{
    base.Enqueue(d);
    OnChanged(EventArgs.Empty);
}
Konstantin Savelev
re-declaring / method-hiding is brittle, non-polymorphic, and brittle; the caller can skip your code simply with a cast.
Marc Gravell