2016-06-19 60 views
1

我感興趣創建一個事件處理對象,您可以訂閱僅一次執行,則動作是自動退訂C#一次(一次火)活動實施

是否有.NET類似本機功能? 以下是對我現在的工作原理:

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

這裏事件被設置爲每秒執行一次。

如何使用在觸發事件不可預測 和防止事件的執行而UnsubscribeOneOffs()方法運行其他對象類似的策略。 我應該使用某種鎖嗎?

回答

1

無需將一次性操作註冊爲OneSecond事件處理程序。只需將它們保存在單獨的列表中。

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