c#达到收集容量或发生超时时触发事件

时间:2016-07-21 17:34:57

标签: c# collections thread-safety observablecollection

我需要在达到Collection容量或发生超时时执行某些操作。

例如,如果我有一个容量为10的列表,超时为10秒则必须等待其中一个"事件"提出要执行某事。

我正在考虑使用 ObservableCollection ,并且在事件 CollectionChanged()中计算集合的项目数,并查看是否等于请求的最大数量允许。

同时我将有一个计时器来控制超时。

有人可以告诉我是否有更好的解决方案?

提前多多感谢。

2 个答案:

答案 0 :(得分:1)

您可以使用所需功能实现自己的收藏。 像这样:

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

使用async / await

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

答案 1 :(得分:0)

如果我这样做,我会使用Microsoft的Reactive Framework(NuGet&#34; Rx-Main&#34;)。然后你可以这样做:

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

因此query有效地监视CollectionChanged事件并计算计数是否等于10,仅当它为10时返回(并返回true),并取一个值。然后它会施加超时,在10.0秒后返回false