2009-02-10 11 views
14

Devo essere in grado di attivare un evento ogni volta che un oggetto viene aggiunto a un Queue<Delegate>.C#: attivazione di un evento quando un oggetto viene aggiunto a una coda

ho creato una nuova classe che estende 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); 
     } 
    } 
} 

E poi attaccato l'evento da un'altra classe, come ad esempio:

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

Ma ogni volta che Enqueue un oggetto (eventQueue.Enqueue(something)), l'evento allegato non viene licenziato.

Cosa mi manca qui?

risposta

25

Se si intende il non generico Queue di classe, allora si può solo ignorare Enqueue:

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

Tuttavia, se si intende il generico Queue<T> di classe, poi notare che non esiste un metodo virtuale adatto per ignorare. Si potrebbe fare meglio incapsulare coda con la propria classe:

(** importante Edit: rimosso classe base !!! **)

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

Tuttavia, guardando il tuo codice, sembra possibile che tu stia utilizzando più thread qui. Se questo è il caso, prendere in considerazione un threaded queue.

+0

Eccellente; Questo e 'esattamente quello che stavo cercando. Grazie Marc per la risposta di qualità. E controllerò anche la coda dei thread che hai menzionato. –

+0

Nota che ho impostato erroneamente una classe base; corretto nel codice ... –

+0

Dal punto di vista del principio di progettazione, è meglio utilizzare la composizione sull'ereditarietà (in senso lato) quindi sostengo la soluzione. – uriDium

0

È necessario eseguire l'override di Enqueue per chiamare OnChanged.

+0

Enqueue non è virtuale nella coda generica

+0

Giusto, è un vero peccato. Immagino che dovresti creare un'interfaccia IQueue e quindi avere la tua implementazione. –

1

provare

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

re-dichiarare/nascondere il metodo è fragile, non polimorfo e fragile; il chiamante può saltare il tuo codice semplicemente con un cast. –

3

ho appena ho scritto su quello che io chiamo un TriggeredQueue. È ispirata alla risposta di Marc Gravell.

Potete trovare il mio post qui: http://joesauve.com/triggeredqueuet

E il Gist qui: http://gist.github.com/jsauve/b2e8496172fdabd370c4

Ha quattro eventi:

  • WillEnqueue
  • WillDequeue
  • DidEnqueue
  • DidDequeue

È possibile collegare in qualsiasi di questi in questo modo:

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

Un trucchetto è che è possibile utilizzare il metodo DidDequeue per dare il via qualche processo per assicurare che la coda è piena facendo una web richiesta o caricamento di alcuni dati da un filesystem, ecc. Uso questa classe nelle app per dispositivi mobili Xamarin per garantire che i dati e le immagini siano pre-memorizzati nella cache al fine di offrire all'utente un'esperienza fluida, invece di caricare le immagini DOPO che scorrono sullo schermo (come potresti vedere su Facebook e innumerevoli altre app).

Problemi correlati