using System.Threading;
public class MyClass : IDisposable
{
private List<int> ints = new List<int>();
private Timer t;
public MyClass()
{
//Create timer in disabled state
t = new Timer(this.OnTimer, null, Timeout.Infinite, Timeout.Infinite);
}
private void DisableTimer()
{
if (t == null) return;
t.Change(Timeout.Infinite, Timeout.Infinite);
}
private void EnableTimer()
{
if (t == null) return;
//Fire timer in 1 second and every second thereafter.
EnableTimer(1000, 1000);
}
private void EnableTimer(long remainingTime)
{
if (t == null) return;
t.Change(remainingTime, 1000);
}
private void OnTimer(object state)
{
lock (ints) //Added since original post
{
DisableTimer();
DoSomethingWithTheInts();
ints.Clear();
//
//Don't reenable the timer here since ints is empty. No need for timer
//to fire until there is at least one element in the list.
//
}
}
public void Add(int i)
{
lock(ints) //Added since original post
{
DisableTimer();
ints.Add(i);
if (ints.Count > 10)
{
DoSomethingWithTheInts();
ints.Clear();
}
if (ints.Count > 0)
{
EnableTimer(FigureOutHowMuchTimeIsLeft());
}
}
}
bool disposed = false;
public void Dispose()
{
//Should I protect myself from the timer firing here?
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
//Should I protect myself from the timer firing here?
if (disposed) return;
if (t == null) return;
t.Dispose();
disposed = true;
}
}
编辑-在我的实际代码中,我在Add和OnTimer的列表中都有锁。当我简化代码以便发布时,我不小心遗漏了它们。
由于计时器是一次性的,所以我在类上实现了一次性模式。我的问题是:我是否需要额外的保护在任何处置方法,以防止任何副作用的计时器事件触发?
我可以很容易地在两种方法中禁用计时器。我知道这不一定会使我100%安全,因为在调用Dispose和禁用计时器之间计时器可能会触发。暂时撇开这个问题不谈,尽我所能保护Dispose方法不受计时器执行的可能性的影响,这是否是一种最佳做法?
现在我考虑了一下,如果列表在Dispose中不是空的,我可能还应该考虑应该怎么做。在对象的使用模式中
应该
那时候就空着吧,但我想一切都有可能。假设在调用Dispose时,列表中还剩下一些项,继续尝试处理它们是好是坏?我想我可以说一句老话:
public void Dispose()
{
if (ints != null && ints.Count > 0)
{
//Should never get here. Famous last words!
}
}
无论列表中是否有任何项都是次要的。我真正感兴趣的是找出处理可能启用的计时器和Dispose的最佳实践。
如果重要的话,这段代码实际上在Silverlight类库中。它根本不与UI交互。
编辑:
我找到了一个很好的解决方案
here
jsw
建议使用OnTrime.TyyTurn/MealOr.EXIT保护OnTimeEnter事件,有效地将OnTime代码放入关键部分。
Michael Burr
发布了一个似乎更好的解决方案,至少对我来说是这样,通过将到期时间设置为所需的间隔并将周期设置为Timeout.Infinite来使用一次性计时器。
对于我的工作,我只希望计时器在列表中至少添加了一项时触发。所以,首先,我的计时器被禁用了。输入Add时,请禁用计时器,使其在添加过程中不会触发。添加项时,处理列表(如果需要)。在离开Add之前,如果列表中有任何项(即如果列表尚未处理),请启用计时器,并将due time设置为
剩余间隔
时间段设置为Timeout.Infinite。
对于一次性计时器,甚至不需要在OnTimer事件中禁用计时器,因为计时器无论如何都不会再次触发。当我离开OnTimer时,我也不必启用计时器,因为列表中不会有任何项目。在再次启用一次性计时器之前,我将等待另一个项目添加到列表中。
谢谢!
using System.Threading;
public class MyClass : IDisposable
{
private List<int> ints = new List<int>();
private Timer t;
public MyClass()
{
//Create timer in disabled state
t = new Timer(this.OnTimer, null, Timeout.Infinite, Timeout.Infinite);
}
private void DisableTimer()
{
if (t == null) return;
t.Change(Timeout.Infinite, Timeout.Infinite);
}
private void EnableTimer()
{
if (t == null) return;
//Fire event in 1 second but no events thereafter.
EnableTimer(1000, Timeout.Infinite);
}
private void DoSomethingWithTheInts()
{
foreach (int i in ints)
{
Whatever(i);
}
}
private void OnTimer(object state)
{
lock (ints)
{
if (disposed) return;
DoSomethingWithTheInts();
ints.Clear();
}
}
public void Add(int i)
{
lock(ints)
{
if (disposed) return;
ints.Add(i);
if (ints.Count > 10)
{
DoSomethingWithTheInts();
ints.Clear();
}
if (ints.Count == 0)
{
DisableTimer();
}
else
if (ints.Count == 1)
{
EnableTimer();
}
}
}
bool disposed = false;
public void Dispose()
{
if (disposed) return;
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
lock(ints)
{
DisableTimer();
if (disposed) return;
if (t == null) return;
t.Dispose();
disposed = true;
}
}
}