2016-07-21 20 views
1

Ich muss etwas ausführen, wenn eine Erfassungskapazität erreicht ist oder eine Zeitüberschreitung auftritt.C# Ein Ereignis auslösen, wenn die Erfassungskapazität erreicht ist oder eine Zeitüberschreitung auftritt

Zum Beispiel, wenn ich eine Liste mit der Kapazität von 10 hatte und eine Zeitüberschreitung von 10 Sekunden warten muss, bis eines der "Ereignisse" ausgelöst wird, um etwas auszuführen.

Ich war ein ObservableCollection und im Falle Collection auf den Einsatz zu denken() die Anzahl der Elemente der Sammlung zählen und sehen, ob auf die Anzahl max von Anfragen erlaubt gleich ist.

Zur gleichen Zeit werde ich einen Timer haben, um das Timeout zu steuern.

Kann mir bitte jemand sagen, ob es eine bessere Lösung gibt?

Vielen Dank im Voraus.

+0

Ich würde ein [AutoResetEvent] (https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent.aspx) auf einem "Watcher" -Thread verwenden. Die WaitOne-Methode kann eine Zeitüberschreitung oder eine Signalisierung durch das CollectionChanged-Ereignis erhalten (wenn die Kapazität erreicht ist). –

Antwort

1

Sie können Ihre eigene Sammlung mit den von Ihnen benötigten Funktionen implementieren. Etwas wie folgt aus:

static void Main() 
     { 
      var list = new MyObservableCollection<int>(10, 10); 

      list.ConditionReachedEvent +=() => 
      { 
       //Do something 
      }; 

      list.StartTimer(); 

      Task.Factory.StartNew(
       () => 
        { 
         // Simulate slow operation 
         Thread.Sleep(12000); 
         for (var i = 0; i < 10; i++) 
         { 
          list.Add(i); 
         } 
        }); 

      Console.Read(); 
     } 

     public sealed class MyObservableCollection<T> : System.Collections.ObjectModel.ObservableCollection<T> 
     { 
      public event Action ConditionReachedEvent = delegate { }; 
      private System.Threading.Timer timer; 
      private readonly int alertThreshold; 
      private long isEventRaised = 0; 
      private readonly int timeout = 0; 

      public MyObservableCollection(int alertThreshold, int timeout) 
      { 
       this.alertThreshold = alertThreshold; 
       this.timeout = timeout * 1000; 
      } 

      public void StartTimer() 
      { 
       Interlocked.Exchange(ref this.isEventRaised, 0); 
       this.StopTimer(); 
       this.timer = new Timer(x => 
       { 
        this.RaiseEvent(); 
       }, null, this.timeout, this.timeout); 
      } 

      private void StopTimer() 
      { 
       if (this.timer != null) 
       { 
        this.timer.Dispose(); 
        this.timer = null; 
       } 
      } 

      protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
      { 
       base.OnCollectionChanged(e); 
       if (this.Count >= this.alertThreshold) 
       { 
        this.RaiseEvent(); 
       } 
      } 

      private void RaiseEvent() 
      { 
       this.StopTimer(); 

       if (Interlocked.CompareExchange(ref this.isEventRaised, 1, 0) != 0) 
       { 
        return; 
       } 

       this.ConditionReachedEvent(); 
      } 
     } 

Mit async/erwarten

static void Main() 
     { 
      var list = new MyObservableCollection<int>(10); 
      list.ConditionReachedEvent +=() => 
      { 

      }; 

      list.Start(10); 

      Task.Run(
       () => 
       { 
        // Simulate slow operation 
        Thread.Sleep(TimeSpan.FromSeconds(12)); 
        for (var i = 0; i < 10; i++) 
        { 
         list.Add(i); 
        } 
       }); 

      Console.Read(); 
     } 


     public sealed class MyObservableCollection<T> : System.Collections.ObjectModel.ObservableCollection<T> 
     { 
      public event Action ConditionReachedEvent = delegate { }; 
      private readonly int alertThreshold; 
      private readonly TaskCompletionSource<object> capacityReached = new TaskCompletionSource<object>(); 

      public MyObservableCollection(int alertThreshold) 
      { 
       this.alertThreshold = alertThreshold; 
      } 

      public async void Start(int timeout) 
      { 
       var timeoutTask = Task.Delay(TimeSpan.FromSeconds(timeout)); 
       var capacityReachedTask = capacityReached.Task; 

       await Task.WhenAny(capacityReachedTask, timeoutTask); 
       this.ConditionReachedEvent(); 
      } 

      protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
      { 
       base.OnCollectionChanged(e); 
       if (this.Count >= this.alertThreshold) 
       { 
        capacityReached.TrySetResult(null); 
       } 
      } 
     } 
0

Wenn ich dies taten, würde ich von Microsoft verwenden Reactive Framework (NuGet "Rx-Main"). Dann könnten Sie dies tun:

var collection = new ObservableCollection<int>(); 

var query = 
    Observable 
     .FromEventPattern< 
      NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
      h => collection.CollectionChanged += h, h => collection.CollectionChanged -= h) 
     .Select(ep => collection.Count == 10) 
     .Where(x => x) 
     .Take(1) 
     .Timeout(TimeSpan.FromSeconds(10.0), Observable.Return(false)); 

query.Subscribe(flag => 
{ 
    if (flag) // capacity 
    { 
    } 
    else //timeout 
    { 
    } 
}); 

So ist die query effektiv überwacht die CollectionChanged Ereignis und berechnet, wenn der Zählwert gleich 10 ist, Filter für nur, wenn es 10 (und kehrt true) und nimmt einen Wert. Dann wird ein Zeitlimit gesetzt, das nach 10,0 Sekunden false zurückgibt.