首页 文章

C#定时器功能和行为

提问于
浏览
0

所以我使用Timer调用函数,但是我希望能够自己调用这个函数 . 我想到的方法是让Timer函数调用实际函数:

public System.Timers.Timer atimer = new System.Timers.Timer();


private void Timer()
        {
            atimer.Elapsed += new System.Timers.ElapsedEventHandler(FunctionCalledByTimer);
            atimer.Interval = 10000;
            atimer.Enabled = true;
        }      

 private void FunctionCalledByTimer(object source, System.Timers.ElapsedEventArgs e)
        {
            CheckOrder();
        }

然后,如果我想在我使用的计时器之外调用该函数:

public void NextPhaseByPlayerInitialized()
        {                              
                atimer.Enabled = false;
                atimer.Enabled = true;
                CheckOrder();                
        }

现在我遇到的问题是CheckOrder有一些变量,它通过递增来改变它们 . 如果我使用计时器,它会很好地工作,它每次都会增加一个 . 然而,奇怪的是如果我手动调用定时器外的函数(也在此过程中重置定时器),从定时器侧到目前为止发生的所有增量再次设置为0 .

它似乎计时器调用的所有内容都与计时器外的所有内容分开,第二个我停止计时器变量返回其原始状态 . 我的问题首先是这个预期的行为,如果是这样,为什么?第二是有解决方法吗?

请事先提供帮助

fullcode:

using System;
using System.Threading;

class Programm
{
    static void Main(string[] args)
    {

        Caller.Init();
        Object.counters[0].Timer();

    }
}

class Caller
{
    public static void Init()
    {
        for (int i = 0; i < Object.counters.Length; i++)
        {
            Object.counters[i] = new Object.Counter
            {
                currentCount = 0,
                atimer = new System.Timers.Timer()
            };
        }
    }
}

class Input
{
    public void PressButton()
    {
        Object.counters[0].NextPhaseByPlayerInitialized();
    }
}

class Object {

    public static Counter[] counters = new Counter[2];

    public struct Counter
    {
        public int currentCount;
        public System.Timers.Timer atimer;

        public void Timer()
        {
            atimer.Elapsed += new System.Timers.ElapsedEventHandler(FunctionCalledByTimer);
            atimer.Interval = 10000;
            atimer.Enabled = true;
        }

        private void FunctionCalledByTimer(object source, System.Timers.ElapsedEventArgs e)
        {
            CheckOrder();
        }

        public void NextPhaseByPlayerInitialized()
        {
            atimer.Enabled = false;
            atimer.Enabled = true;
            CheckOrder();
        }
        private void CheckOrder()
        {
            Console.WriteLine("currentCount: {0}", currentCount);
            currentCount++;
        }
    }    
}

1 回答

  • 3

    Short answer:

    • 永远不要在C#中使用结构 . 您可以考虑使用 struct s的唯一时间是 struct 是小而且 immutable (所有字段都标记为 readonly 且永不改变) .

    • 不要使用 static 对象实例 . 他们是邪恶的 .

    • 不要使用 public static 对象实例 . 他们真的非常邪恶 .

    Long answer:

    struct 是C#中的value type,意味着它是按值传递的 . 这意味着,每当您将 struct 变量传递给函数时,它将获得此结构的副本,并对函数体内的副本进行操作 . 一旦它返回,所有的变化都消失了 .

    在这种情况下,会发生什么有点不同,但仍然同样险恶:将结构中的方法附加到timer事件的行实际上创建 copy structboxes it(分配一个托管堆对象,其中包含一个副本你的 struct ) .

    这意味着您所看到的字段的所有更改都不会实际发生在数组内的结构中,除非在调用 Object.counters[0].NextPhaseByPlayerInitialized() 时调用实际的 Object.counters[0] 上的方法 .

    您可以重写 CheckOrder 方法以查看计时器实际上是否获得了自己的副本:

    private void CheckOrder()
    {
        // this is working on a boxed copy
        currentCount++;
        Console.WriteLine("this.currentCount: {0}", currentCount);
    
        // this is the global instance
        Console.WriteLine("counters[0].currentCount: {0}", counters[0].currentCount);
    }
    

    所以,摆脱结构 . 另外,如果你正在编写一个游戏,让计时器在不同的线程上开火可能是一个坏主意 .

相关问题