我想触发一个定时器,在将来某个时刻执行一次。我想使用一个lambda表达式来简化代码。所以我想做一些类似于...
(new System.Threading.Timer(() => { DoSomething(); },
null, // no state required
TimeSpan.FromSeconds(x), // Do it in x seconds
TimeSpan.FromMilliseconds(-1)); // don't repeat
我认为这是非常整洁的。但是在这个例子中,Timer对象没有被释放。解决这个问题的最好方法是什么?或者,我应该在这里使用一种完全不同的方法吗?
8条答案
按热度按时间sxissh061#
这种做法是有缺陷的。
您正在内存中创建一个对象,但没有对其进行引用。这意味着计时器对象可用于垃圾回收。虽然此代码在某些时候可以工作,但您无法预测垃圾回收何时启动并删除计时器。
例如,在下面的代码中,我强制执行垃圾收集,这会导致计时器永远不会触发。
niwlg2el2#
这将完成你想要的,但我不确定这是最好的解决方案。我认为这是一个简短和优雅的东西,但可能更令人困惑和难以遵循比它的价值。
piztneat3#
不使用计时器,而是利用线程池:
这在垃圾回收中仍然存在,因为您不必保留对任何内容的引用。
vfwfrxfs4#
你可以 Package 这个计时器类...
iaqfqrcu5#
定时器对象 * 可能 * 实现了一个析构函数。你可以在文档或反射器中很容易地验证这一点。
如果这是真的,你就不用担心,除非这段代码被调用了很多次,在这种情况下,你应该争取确定性地释放定时器,这意味着你会持有一个定时器数组。
lskq00tm6#
如果您有Dispatcher并希望位于UI(Dispatcher)线程中,请使用以下命令:
这个函数不是异步的,因为你不想在你的函数中等待。如果你想在不同的时间调度多个事件,这个方法可能会很有用,但也许你真的需要下面的方法:
它做同样的事情,但是需要在函数结束时执行wait。
由于您可能没有Dispatcher或者不想使用它,但仍然希望在不同的时间调度多个操作,因此我将使用一个线程:
如果您希望避免异步,我建议不要使用线程池,并将await
Task.Delay(delayMs)
调用替换为Thread.Sleep(delayMs)
调用y53ybaqx7#
例如,可以使用
TaskCompletionSource
:然后把它叫做:
或直接调用:
ltqd579y8#