2016-06-19 59 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(); 
      } 
    } 
}