developer's diary

最近はc#のエントリが多いです

C# (dotnetcore)で標準出力を利用して進行中のスピナーを作る (3)

前回の記事

mitsugeek.net

前回見つけた矛盾を修正する

前回見つけた矛盾、 Value設定後に、Maximum、Minimumに値を設定すると不整合になる可能性を潰す。

  • Maximumを設定した際に、Maximum < Valueの場合、ValueにMaximumを設定
  • Minimumを設定した際に、Minimum > Valueの場合、ValueにMinimumを設定

プロパティのセッターを修正

        private int minimum = 0;

        /// <summary>コントロールの範囲の最小値を取得または設定します。</summary>
        public int Minimum {
            get
            {
                return minimum;
            }
            set
            {
                if (value < 0)
                    throw new ArgumentException("プロパティに対して指定された値が 0 未満です。");

                minimum = value;

                if (this.minimum > this.value)
                {
                    this.value = this.minimum;
                }
            }
        }

        private int maximum = 100;

        /// <summary>コントロールの範囲の最大値を取得または設定します。</summary>
        public int Maximum {
            get
            {
                return maximum;
            }
            set
            {
                if (value < 0)
                    throw new ArgumentException("プロパティに対して指定された値が 0 未満です。");

                maximum = value;

                if (this.maximum < this.value)
                {
                    this.value = this.maximum;
                }
            }
        }

テスト追加

        [Fact]
        public void MinimumSetTest()
        {
            ConsoleProgressSpiner c = new ConsoleProgressSpiner();
            c.Value = 10;
            Assert.Equal(10, c.Value);
            c.Minimum = 20;
            Assert.Equal(20, c.Minimum);
            Assert.Equal(20, c.Value);
        }

        [Fact]
        public void MaximumSetTest()
        {
            ConsoleProgressSpiner c = new ConsoleProgressSpiner();
            c.Value = 90;
            Assert.Equal(90, c.Value);
            c.Maximum = 80;
            Assert.Equal(80, c.Maximum);
            Assert.Equal(80, c.Value);
        }

スピナーの出力部分の実装

少しいまいち感が拭えないが、第1回のソースを元に、エイヤーで移植。

        /// <summary>描画</summary>
        private void update()
        {
            if (this.Maximum == this.Value)
            {
                //色を戻す
                Console.ResetColor();

                //カーソル位置を変更
                Console.SetCursorPosition(0, Console.CursorTop);

                //終了の表示
                Console.WriteLine("Done! ");
            }
            else
            {
                decimal oneMeter = new decimal(100) / (this.Maximum - this.Minimum);
                int nowIndex = Decimal.ToInt32(oneMeter * (this.Value - this.Minimum));

                //色変更
                Console.ForegroundColor = ConsoleColor.Green;
                Console.BackgroundColor = ConsoleColor.Black;

                //アニメーションの表示
                Console.Write(bars[nowIndex % bars.Length]);

                //進捗率の表示
                Console.Write("{0, 3:d0}%", nowIndex);

                //カーソル位置を変更
                Console.SetCursorPosition(0, Console.CursorTop);

                //色を戻す
                Console.ResetColor();
            }
        }

この部品を利用する箇所の実装

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

            ConsoleProgressSpiner progressSpiner = new ConsoleProgressSpiner();
            progressSpiner.Minimum = 0;
            progressSpiner.Maximum = 1000;
            progressSpiner.Value = 0;

            for(int i = progressSpiner.Minimum; i <= progressSpiner.Maximum; i++)
            {
                progressSpiner.Value = i;
                //一時停止
                System.Threading.Thread.Sleep(10);
            }

        }
    }

課題

  • Consoleへの操作部分のテストをどうするか。(Moqの利用? DIの利用?)
  • updateメソッドの分解(メソッドが長い)

ひとまず。ここまで。続きは次回。

mitsugeek.net