2016-06-19 4 views
1

Ich bin interessiert ein Event-Handling-Objekt erstellen, die Sie nur für eine einmalige Ausführung abonnieren und dann ist die Aktion automatisch abgemeldetC# One Time (Feuer einmal) Veranstaltungen Umsetzung

Gibt es ähnliche nativen Funktionalität in .NET? Hier ist was für mich jetzt:

public class CustomTimer 
{ 
    private event Action OneSecond; 

    private readonly Timer timer; 

    // Registered actions that should be called only once 
    private readonly ICollection<Action> oneOffs; 

    public CustomTimer() 
    { 
     this.timer = new Timer { Interval = 1000 }; 
     this.timer.Elapsed += this.OnOneSecond; 
     this.oneOffs = new HashSet<Action>(); 
    } 

    public bool IsRunning => this.timer.Enabled; 

    public void Start() 
    { 
     this.timer.Start(); 
    } 

    public void Stop() 
    { 
     this.timer.Stop(); 
    } 

    public void Subscribe(Action callback) 
    { 
     this.OneSecond += callback; 
    } 

    public void SubscribeOnce(Action callback) 
    { 
     this.oneOffs.Add(callback); 
     this.Subscribe(callback); 
    } 

    public void Unsubscribe(Action callback) 
    { 
     this.OneSecond -= callback; 
     this.oneOffs.Remove(callback); 
    } 

    protected virtual void OnOneSecond(object sender, ElapsedEventArgs elapsedEventArgs) 
    { 
     this.OneSecond?.Invoke(); 
     this.UnsubscribeOneOffs(); 
    } 

    private void UnsubscribeOneOffs() 
    { 
     if (this.oneOffs.Count > 0) 
     { 
      foreach (var action in this.oneOffs) 
      { 
       this.OneSecond -= action; 
      } 

      this.oneOffs.Clear(); 
     } 
    } 
} 

Hier werden die Ereignisse gesetzt werden jede Sekunde auszuführen.

Wie kann ich ähnliche Strategie in anderen Objekt, das Ereignisse unvorhersehbar und verhindern Ereignisse Ausführung, während die UnsubscribeOneOffs() Verfahren läuft auslösen. Sollte ich irgendeine Art von Schloss benutzen?

Antwort

1

Es ist nicht erforderlich, einmalige Aktionen als OneSecond Event-Handler zu registrieren. Behalte sie einfach in einer separaten Liste.

public class CustomTimer 
{ 
    List<Action> _oneTimeActions = new List<Action>(); 

    public void SubscribeOnce(Action handler) 
    { 
     lock(_oneTimeActions) 
     { 
      _oneTimeActions.Add(handler); 
     } 
    } 


    protected virtual void OnOneSecond(object sender, ElapsedEventArgs elapsedEventArgs) 
    { 

      // get a local copy of scheduled one time items 
      // removing them from the list. 
      Action[] oneTimers; 

      lock(_oneTimeActions) 
      { 
       oneTimers = _oneTimeActions.ToArray(); 
       _oneTimeActions.Clear(); 
      }  

      // Execute periodic events first 
      this.OneSecond?.Invoke(); 

      // Now execute one time actions 
      foreach(var action in oneTimers) 
      { 
       action(); 
      } 
    } 
}