C# 在类的所有实例中同步计时器的好方法是什么?
也就是说,我有一个包含静态System.Threading.Timer的类,我想同步所有对象中的计时器。下面是一个例子,我想实现的是让所有对象同时调用C# 在类的所有实例中同步计时器的好方法是什么?,c#,timer,singleton,static-classes,C#,Timer,Singleton,Static Classes,也就是说,我有一个包含静态System.Threading.Timer的类,我想同步所有对象中的计时器。下面是一个例子,我想实现的是让所有对象同时调用DoStuff(): public class TestClass { public static Timer timer; public TestClass() { TimerCallback callback = DoStuff; timer = new Timer(callback, timer
DoStuff()
:
public class TestClass {
public static Timer timer;
public TestClass() {
TimerCallback callback = DoStuff;
timer = new Timer(callback, timer, 0, 500);
}
public void DoStuff(object source) {
// Do stuff
}
}
由于计时器引用存储在
静态
字段中,因此一次只能有一个计时器实例可用。所以我不清楚你所说的“同步计时器[复数]”是什么意思
如果希望类的每个实例在单个计时器的同一个刻度上执行其DoStuff()
方法,在我看来,正确的方法是维护单个静态处理程序,该处理程序调用每个实例更新的委托实例。例如:
public class TestClass {
private static class TimerHandler
{
public static event TimerCallback TimerHandlers;
private static readonly Timer timer = new Timer(TimerHandlerCallback, null, 0, 500);
private static void TimerHandlerCallback(object state)
{
TimerHandlers?.Invoke(timer);
}
}
public TestClass() {
TimerHandler.TimerHandlers += DoStuff;
}
public void DoStuff(object source) {
// Do stuff
}
}
注:
- 无论你最后做什么,我看不出有任何理由将
字段计时器
公开
- 我将计时器包装在一个嵌套的静态类中,因为这样做允许我用一个事件公开计时器,这反过来允许我忽略回调委托的线程安全修改问题,因为编译器将自动为此生成必要的代码
- 您最初将
作为值传递给构造函数的timer
参数。现在还不清楚你打算怎么做。下面是实际发生的情况:计时器第一次初始化时,字段的值是state
,因此null
参数是state
,这就是传递给处理程序的内容。对于null
的每个新实例,该实例将创建一个新计时器,但使用先前创建的计时器实例作为TestClass
值。在状态
的每个实例中,当调用其TestClass
方法时,它将接收到由DoStuff()
对象的前一个实例创建的计时器的引用,或者为创建的TestClass
对象的第一个实例的TestClass
。null
,我只是在没有
值的情况下初始化计时器(传递状态
),然后在调用委托时传递计时器引用本身。这对我来说比你的代码所做的更有意义null
- 静态事件总是必须非常小心地使用,因为它们本身总是存在的,并且它们隐式地保留对订阅该事件的任何对象的引用。使用上述方法,您的
对象将永远不会被垃圾收集,因为没有从计时器事件中取消订阅对象的机制。您可能想考虑将一个方法添加到您的<代码> TestClass <代码>对象中,该对象在该事件未订阅的情况下,调用代码可以在它准备丢弃一个给定的<代码> TestClass >代码>对象之前调用。TestClass
BR/>这是否是实际需要的,我不知道。你的问题没有足够的背景。如果这些对象永远不需要GC'ed,那么您可以跳过这一步。如果您确实需要这样做,您可能需要考虑实现<代码> IDISPOSTABLE <代码>作为调用该方法的方便机制(即使您的代码>处理()/代码>方法调用它),所以a)可以使用<代码>使用语句来处理对象的生命周期,和b)以便接口实现的存在提醒您需要手动管理对象的生存期。在这里实现
的一个警告(除了所有常见的其他警告之外)是,您不能依赖终结器作为错误代码的备份,因为只有当对象实际上符合GC'ed条件时,终结器才起作用,在这种情况下,只有调用IDisposable
Dispose()
此问题的另一个替代方案是使用弱引用实现
事件。如果这是在WPF程序的上下文中,则可以使用timerhandler
类来简化此过程。如果不是,您可能会发现不值得费心学习如何正确使用弱引用,尤其是在事件上下文中。同样,如果没有更多的背景,我很难说。无论哪种方式,使用弱引用的好处是事件代码保留的引用本身不会阻止对象被GC’ed;好处是,新的挑战更加自动化……一旦解决了它,就完成了,而不必记住每次创建WeakEventManager
对象的实例时,都需要在以后清理它。当然,缺点是从概念上讲,弱引用可能比在丢弃对象之前必须清理对象的基本思想更难理解TestClass
System.Timers.Timer
一起将解决您的问题。谢谢。但有什么是无效的?它应该只是一些重命名,并从实际运行的代码中删除行?看起来您正试图在构造函数中声明成员数据——如果它应该是成员,则将其放入类中;如果它应该是局部变量,则删除public
和static
关键字。啊,是的。固定的。