C#One Time(Fire one)活动实施

时间:2016-06-19 21:38:03

标签: c# .net events

我有兴趣创建一个事件处理对象,您可以只订阅一次执行,然后动作自动取消订阅

.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 个答案:

答案 0 :(得分: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();
          }
    }
}