Awful nested timers, how do I refactor?

2019-09-06 10:34发布

问题:

I've a method consisting of an ugly 13 parameters, but I can't figure out how to turn these into proper submethods and still function exactly the same, stopping after three iterations, using the correct parameters, closing off with a different method, etc. Would someone help me in the right direction?

//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();
                           };
                   };
            };
    }

回答1:

Use async/await and all your troubles go away!

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());

}


回答2:

You asked for a direction... A step in the right direction is:

  • Replace all anonymous methods with real methods (with less code than the curent method)
  • Make less parameters by put all parameters that ends with a number in one class