【问题标题】:Awful nested timers, how do I refactor?糟糕的嵌套计时器,我该如何重构?
【发布时间】:2014-04-12 19:21:55
【问题描述】:

我有一个由丑陋的 13 个参数组成的方法,但我不知道如何将这些转换为正确的子方法,并且仍然功能完全相同,在使用正确的参数进行三次迭代后停止,并以不同的方法等。有人会在正确的方向上帮助我吗?

//Three part animation
    public void SetPlayerAnimation(int location, int x1, int y1, TimeSpan duration1, string sprite1, int x2, int y2, TimeSpan duration2, string sprite2, int x3, int y3, TimeSpan duration3, string sprite3, string endsprite)
    {
        //Get the sprite object to be animated
        TranslateTarget = "Sprite" + location.ToString();
        OnPropertyChanged("TranslateTarget");

        //Start first part
        RunAnimation(location, x1, y1, duration1, sprite1);

        var timer = new DispatcherTimer();
        timer.Interval = duration1;
        timer.Start();
        timer.Tick += (s, args) =>
            {
                //Start second part
                RunAnimation(location, x2, y2, duration2, sprite2);

                timer.Stop();

                var timer2 = new DispatcherTimer();
                timer2.Interval = duration2;
                timer2.Start();
                timer2.Tick += (s2, args2) =>
                   {
                       //Start third part
                       RunAnimation(location, x3, y3, duration3, sprite3);
                       timer2.Stop();

                       var timer3 = new DispatcherTimer();
                       timer3.Interval = duration2;
                       timer3.Start();
                       timer3.Tick += (s3, args3) =>
                           {
                               //End with a final sprite
                               SetPlayerSprite(location, endsprite);
                               timer3.Stop();
                           };
                   };
            };
    }

【问题讨论】:

  • 运行一个计时器,或者甚至是一个适当的游戏循环。每次计时器滴答作响或游戏循环跳动时,检查时间,如果有任何内容需要更新,请更新它。
  • 嗯,我正在编写的程序是非常程序化的。每 20 秒左右有一次命令,一旦动画被触发,它应该简单地“运行”,它总是完成,并且在它开始后永远不会改变它的行为。完整的游戏循环会不会有点矫枉过正?

标签: c# timer delegates refactoring


【解决方案1】:

使用 async/await,所有的麻烦都会消失!

public void SetPlayerAnimation(int location, int x1, int y1, TimeSpan duration1, string sprite1, int x2, int y2, TimeSpan duration2, string sprite2, int x3, int y3, TimeSpan duration3, string sprite3, string endsprite)
{
    //Get the sprite object to be animated
    TranslateTarget = "Sprite" + location.ToString();
    OnPropertyChanged("TranslateTarget");
    Task.Factory.StartNew(
        async () => {
            RunAnimation(location, x1, y1, duration1, sprite1);
            await Task.Delay(duration1);
            RunAnimation(location, x2, y2, duration2, sprite2);
            await Task.Delay(duration2);
            RunAnimation(location, x3, y3, duration3, sprite3);
            await Task.Delay(duration2);
            SetPlayerSprite(location, endsprite);

        }, // this will use current synchronization context
        CancellationToken.None, 
        TaskCreationOptions.None, 
        TaskScheduler.FromCurrentSynchronizationContext());

}

【讨论】:

  • 那么……漂亮。我收到一个错误,“必须在与 DependecyObject 相同的线程上创建 DependencySource”。这是一个新的 SO 问题,还是可以在这里回答?
  • 好的,你需要捕获ui同步上下文,所以你应该使用Task.Factory.StartNew代替Task.Run。见编辑。未经测试。
  • Sepnder,StartNew 在这里没有意义(或Run,就此而言)。您也可以将这些操作内联并创建整个方法async。如果您可以访问代表 UI 线程的 SyncrhonizationContext,情况会有所不同,但实际上,您要么在 UI 线程中,而 StartNew 毫无意义,要么您不在 UI 线程中,而 @987654327 @仍然毫无意义。
  • 我错过了代码本身已更新。 StartNew 和 TaskScheduler.FromCurrentSyncContext 使代码运行良好!
  • @Servy,我不想讨论使整个调用堆栈异步的问题,所以使用 StartNew 意味着我可以不用担心。当然,如果 OP 有信心,他们可能会选择将整个方法标记为异步,并可能在调用堆栈中向上工作。我只是想保持简单。
【解决方案2】:

你问了一个方向......朝着正确方向迈出的一步是:

  • 用真实方法替换所有匿名方法(代码比当前方法少)
  • 将所有以数字结尾的参数放在一个类中,从而减少参数

【讨论】:

  • 从参数集中创建一个类是有意义的,我现在就这样做。我不确定如何用真实方法替换所有匿名方法,但每次迭代都有细微的差异,这使得它非常困难。
  • "(s, args) =>", "(s2, args2)" 和 "(s3, args3) 之后的代码现在是匿名方法,但您可以用 3 种不同的真实方法替换它.
  • 啊哈,我明白了!是的,这比我预期的更合乎逻辑。仅仅因为代码不可重用并不意味着如果我拆分它就不会更好地维护。现在要弄清楚如何将多个参数传递给 timer.Tick 函数,但我相信我能弄清楚。
  • 使用命名方法而不是匿名方法会使这段代码变得更加混乱,因为他将失去关闭相关信息的能力。将这些信息传递给指定方法所需的工作几乎肯定会比现有方法更糟糕。
  • @Servy 许多匿名方法使方法变长,使其更难阅读。我更喜欢单个响应,因为单独方法的名称告诉您方法的作用,没有与责任无关的参数,而且更容易进行单元测试。
猜你喜欢
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-15
  • 2021-10-02
  • 1970-01-01
  • 2021-03-27
  • 1970-01-01
相关资源
最近更新 更多