我想要一些非常简单的东西
// increment counter
Interlocked.Increment(ref _counter);
// automatically decrement counter after 1 sec
Timer timer = new Timer((o) => {
Interlocked.Decrement(ref _counter);
(o as Timer).Dispose();
}, timer, 1000, Timeout.Infinite);
然而,此代码不可编译
使用未分配的本地变量'计时器'
任何简单的方法来解决这个问题?它必须是Threading.Timer
。
PS:我不确定我必须致电Dispose
,它显然是未经管理的资源,它是IDisposable
,仍在msdn他们发出警告
只要您使用Timer,就必须保留对它的引用。与任何托管对象一样,当没有对它的引用时,Timer会进行垃圾回收。定时器仍处于活动状态这一事实并不能阻止它被收集。
我真的希望它被收集(自动处理?)。那么,处置还是不处置?
答案 0 :(得分:6)
有一种模式:
Timer timer = null;
timer = new Timer...
现在你可以在lambda体中使用timer
。这基本上是一种让编译器在做同样事情时感到高兴的方法。
请务必丢弃该计时器。定时器可能由OS句柄资源备份(我认为CLR实现改变了几次)。我相信计时器还包含GC手柄。没有处理的大部分时间是无害的。但是谁知道你可以用大量不受控制的计时器引发的稀有资源耗尽。
进行一些代码审查:如果您希望演员表始终有效,请不要使用as
,因为as
表示失败是预期的情况。不是:(o as Timer)
。相反:((Timer)o)
。
答案 1 :(得分:3)
如果您不保留对它的引用,则自行处理将不起作用。即使它不是周期性的,你也有可能收集垃圾。因此,它可能是垃圾收集,甚至在它第一次滴答之前。
只要您使用Timer,就必须保留对它的引用。如 使用任何托管对象时,Timer都会进行垃圾回收 没有提及它。 Timer仍然有效的事实 不会阻止它被收集。
另一方面,它会通过它的终结器释放,即使你不处理它(虽然不是一个好的做法,依靠这个)。这可以在Timer的源代码on ReferenceSource中看到。
答案 2 :(得分:0)
如果你处理它很重要,你应该试试这个:
class Foo {
private Timer _timer;
...
public void IncrementForASecond()
{
Interlocked.Increment(ref _counter);
if(_timer != null)
_timer.Dispose();
_timer = new Timer((o) => {
Interlocked.Decrement(ref _counter);
}, null, 1000, Timeout.Infinite);
}
通过这种方式,您可以确保始终拥有对计时器的引用,并确保在创建新计时器之前处理之前的计时器。