2009-02-10 9 views
14

Ich muss in der Lage sein, ein Ereignis auszulösen, wenn ein Objekt zu einer Queue<Delegate> hinzugefügt wird.C#: Auslösen eines Ereignisses, wenn ein Objekt zu einer Warteschlange hinzugefügt wird

habe ich eine neue Klasse, die Queue erweitert:

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

Und dann angebracht, um das Ereignis aus einer anderen Klasse, wie solche:

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

Aber immer, wenn ich enqueue ein Objekt (eventQueue.Enqueue(something)), Das angehängte Ereignis wird nicht ausgelöst.

Was fehlt mir hier?

Antwort

25

Wenn Sie die nicht-generische Queue Klasse bedeuten, dann können Sie nur Enqueue außer Kraft setzen:

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

Wenn Sie jedoch die allgemeine Queue<T> Klasse bedeuten, dann beachten Sie, dass es keine geeignete virtuelle Methode ist außer Kraft zu setzen. Sie könnten besser encapsulate tun die Warteschlange mit Ihrer eigenen Klasse:

(** wichtig edit: entfernte Basisklasse !!! **)

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

jedoch in Ihrem Code sucht, es scheint möglich, dass Sie hier mehrere Threads verwenden. Wenn dies der Fall ist, betrachten Sie stattdessen eine threaded queue.

+0

Ausgezeichnet; Das ist genau das, wonach ich gesucht habe. Danke Marc für die qualitativ hochwertige Antwort. Und ich werde auch über die Threaded Queue, die du erwähnt hast, nachsehen. –

+0

Beachten Sie, dass ich eine Basisklasse falsch festgelegt habe; im Code behoben ... –

+0

Aus einer Design-Prinzip-Perspektive ist es besser, Zusammensetzung über Vererbung (allgemein gesprochen) zu verwenden, damit ich Ihre Lösung unterstütze. – uriDium

0

Sie müssen die Enqueue überschreiben, um OnChanged aufzurufen.

+0

Enqueue ist nicht auf der generischen Warteschlange virtuell

+0

Richtig, das ist eine Schande. Ich denke, Sie müssten eine IQueue-Schnittstelle erstellen und dann Ihre eigene Implementierung haben. –

1

versuchen

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

Re-Deklaration/Method-Hiding ist spröde, nicht-polymorph und spröde; Der Anrufer kann Ihren Code einfach mit einem Cast überspringen. –

3

Ich habe aufzuschreiben nur auf das, was ich ein TriggeredQueue nennen. Es ist die Antwort von Marc Gravell inspiriert.

Sie meinen Beitrag finden Sie hier: http://joesauve.com/triggeredqueuet

Und das Gist hier: http://gist.github.com/jsauve/b2e8496172fdabd370c4

Es hat vier Veranstaltungen:

  • WillEnqueue
  • WillDequeue
  • DidEnqueue
  • DidDequeue

Sie können wie so in jeder dieser Haken:

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

Ein netter Trick ist, dass Sie die DidDequeue Methode verwenden können, um einen Prozess zu beginnen, um sicherzustellen, dass die Warteschlange, indem eine Bahn voll ist Ich verwende diese Klasse in Xamarin Mobile Apps, um sicherzustellen, dass Daten und Bilder vorab gecached werden, um eine reibungslose Benutzererfahrung zu bieten, anstatt Bilder zu laden, NACHDEM sie auf den Bildschirm geblättert haben (wie z Sie könnten in Facebook und unzähligen anderen Apps sehen).

Verwandte Themen