首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在类的所有实例中同步定时器的好方法是什么?

在类的所有实例中同步定时器的好方法是什么?
EN

Stack Overflow用户
提问于 2017-02-20 22:51:43
回答 1查看 164关注 0票数 1

也就是说,我有一个包含静态System.Threading.Timer的类,我想同步所有对象中的定时器。例如,我想要实现的是让所有对象同时调用DoStuff()

代码语言:javascript
复制
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
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-02-21 01:09:28

因为计时器引用存储在static字段中,所以每次只有一个计时器实例可用。所以我不清楚你所说的“同步定时器复数”是什么意思。

如果您希望类的每个实例在单个计时器的相同勾号上执行其DoStuff()方法,那么在我看来,正确的方法是维护一个静态处理程序,该处理程序调用由每个实例更新的委托实例。例如:

代码语言:javascript
复制
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字段public
  • 我将计时器封装在一个嵌套的静态类中,因为这样做允许我用事件公开计时器,而这反过来又允许我忽略回调委托的线程安全修改问题,因为编译器将自动为此生成必要的代码。
  • 您最初是将timer作为值传递给构造函数的state参数。现在还不清楚你打算在那之前发生什么。下面是发生的事情:第一次初始化计时器时,字段的值是null,所以state参数是null,这就是传递给处理程序的内容。对于TestClass的每个新实例,该实例将创建一个新的计时器,但使用以前创建的timer实例作为state值。在TestClass的每个实例中,当调用其DoStuff()方法时,它将接收对由TestClass对象的前一个实例创建的计时器的引用,或对创建的TestClass对象的第一个实例的null的引用。

相反,我只是在没有state值的情况下初始化计时器(传递null),然后在调用委托时传递定时器引用本身。这对我来说比你的代码做的更有意义。

  • 静态事件总是必须非常小心地使用,因为它们本身总是存在的,并且它们隐式地保留对订阅该事件的任何对象的引用。有了以上所述,您的TestClass对象将永远不会被垃圾收集,因为没有从timer事件中取消订阅对象的机制。您可能需要考虑向您的TestClass对象添加一个方法,该方法取消对事件的订阅,并且调用代码可以在它准备丢弃给定的TestClass对象之前调用该方法。

是否真的需要这样做,我无从得知。你的问题没有足够的背景。如果这些对象不需要GC‘’ed,那么您可以跳过这个。如果确实需要这样做,您可能需要考虑实现IDisposable作为调用方法的方便机制(即让您的Dispose()方法调用它),这样a)您可以使用using语句来处理对象的生存期,而b)接口实现的存在提醒您需要手动管理对象的生存期。这里关于实现IDisposable的一个警告(除了所有通常的其他警告)是,您将无法依赖终结器作为buggy代码的备份,因为只有当一个对象实际上有资格被GC‘’ed,在这种情况下,只有调用Dispose()时才能工作。

这个问题的另一个替代方法是使用弱引用实现TimerHandlers事件。如果这是在WPF程序的上下文中,则可以使用WeakEventManager类来简化操作。如果不是,您可能会发现学习如何正确使用弱引用是不值得的,特别是在事件的上下文中。再一次,我很难在没有更多背景的情况下说。不管怎样,使用弱引用的好处是事件代码保存的引用本身不会阻止对象被GC‘编辑。您将一个实现细节挑战替换为另一个实现细节挑战;好处是新的挑战是更自动的…。一旦您解决了它,您就完成了,而不是每次创建TestClass对象的实例时都要记住,以后您必须清理它自己。缺点当然是,在概念上,弱引用可能比必须在丢弃对象之前清理对象的基本想法更难理解。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42355636

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档