148

これだけ - C# コンソール アプリケーションにタイマーを追加するにはどうすればよいですか? コーディング例を提供していただければ幸いです。

4

12 に答える 12

141

これは非常に良いことですが、時間の経過をシミュレートするには、時間がかかるコマンドを実行する必要があり、2 番目の例で非常に明確です。

ただし、for ループを使用して一部の機能を永久に実行するスタイルは、大量のデバイス リソースを必要とするため、代わりにガベージ コレクターを使用してそのようなことを行うことができます。

この変更は、同じ本 CLR Via C# Third Ed のコードで確認できます。

using System;
using System.Threading;

public static class Program 
{
   private Timer _timer = null;
   public static void Main() 
   {
      // Create a Timer object that knows to call our TimerCallback
      // method once every 2000 milliseconds.
      _timer = new Timer(TimerCallback, null, 0, 2000);
      // Wait for the user to hit <Enter>
      Console.ReadLine();
   }

   private static void TimerCallback(Object o) 
   {
      // Display the date/time when this method got called.
      Console.WriteLine("In TimerCallback: " + DateTime.Now);
   }
}
于 2011-10-23T08:25:48.833 に答える
74

System.Threading.Timer クラスを使用します。

System.Windows.Forms.Timer は、主にシングル スレッド (通常は Windows フォーム UI スレッド) で使用するために設計されています。

.NET フレームワークの開発の早い段階で追加された System.Timers クラスもあります。ただし、これはとにかく System.Threading.Timer の単なるラッパーであるため、代わりに System.Threading.Timer クラスを使用することをお勧めします。

また、Windows サービスを開発していて、タイマーを定期的に実行する必要がある場合は、常に静的 (VB.NET で共有) System.Threading.Timer を使用することをお勧めします。これにより、タイマー オブジェクトの時期尚早なガベージ コレクションを回避できます。

コンソール アプリケーションのタイマーの例を次に示します。

using System; 
using System.Threading; 
public static class Program 
{ 
    public static void Main() 
    { 
       Console.WriteLine("Main thread: starting a timer"); 
       Timer t = new Timer(ComputeBoundOp, 5, 0, 2000); 
       Console.WriteLine("Main thread: Doing other work here...");
       Thread.Sleep(10000); // Simulating other work (10 seconds)
       t.Dispose(); // Cancel the timer now
    }
    // This method's signature must match the TimerCallback delegate
    private static void ComputeBoundOp(Object state) 
    { 
       // This method is executed by a thread pool thread 
       Console.WriteLine("In ComputeBoundOp: state={0}", state); 
       Thread.Sleep(1000); // Simulates other work (1 second)
       // When this method returns, the thread goes back 
       // to the pool and waits for another task 
    }
}

Jeff Richter著CLR Via C#という本から。ちなみに、この本では 23 章で 3 種類のタイマーの背後にある理論的根拠が説明されているので、強くお勧めします。

于 2008-10-09T06:09:42.213 に答える
26

以下は、単純な 1 秒のタイマー ティックを作成するコードです。

  using System;
  using System.Threading;

  class TimerExample
  {
      static public void Tick(Object stateInfo)
      {
          Console.WriteLine("Tick: {0}", DateTime.Now.ToString("h:mm:ss"));
      }

      static void Main()
      {
          TimerCallback callback = new TimerCallback(Tick);

          Console.WriteLine("Creating timer: {0}\n", 
                             DateTime.Now.ToString("h:mm:ss"));

          // create a one second timer tick
          Timer stateTimer = new Timer(callback, null, 0, 1000);

          // loop here forever
          for (; ; )
          {
              // add a sleep for 100 mSec to reduce CPU usage
              Thread.Sleep(100);
          }
      }
  }

結果の出力は次のとおりです。

    c:\temp>timer.exe
    Creating timer: 5:22:40

    Tick: 5:22:40
    Tick: 5:22:41
    Tick: 5:22:42
    Tick: 5:22:43
    Tick: 5:22:44
    Tick: 5:22:45
    Tick: 5:22:46
    Tick: 5:22:47

編集:ハード スピン ループをコードに追加することは、CPU サイクルを無駄に消費するため、決して良い考えではありません。この場合、そのループは、アプリケーションが閉じないようにするためだけに追加され、スレッドのアクションを監視できるようにしました。しかし、正確性と CPU 使用率を下げるために、単純な Sleep 呼び出しがそのループに追加されました。

于 2008-10-09T06:24:53.603 に答える
16

少し楽しみましょう

using System;
using System.Timers;

namespace TimerExample
{
    class Program
    {
        static Timer timer = new Timer(1000);
        static int i = 10;

        static void Main(string[] args)
        {            
            timer.Elapsed+=timer_Elapsed;
            timer.Start(); Console.Read();
        }

        private static void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            i--;

            Console.Clear();
            Console.WriteLine("=================================================");
            Console.WriteLine("                  DEFUSE THE BOMB");
            Console.WriteLine(""); 
            Console.WriteLine("                Time Remaining:  " + i.ToString());
            Console.WriteLine("");        
            Console.WriteLine("=================================================");

            if (i == 0) 
            {
                Console.Clear();
                Console.WriteLine("");
                Console.WriteLine("==============================================");
                Console.WriteLine("         B O O O O O M M M M M ! ! ! !");
                Console.WriteLine("");
                Console.WriteLine("               G A M E  O V E R");
                Console.WriteLine("==============================================");

                timer.Close();
                timer.Dispose();
            }

            GC.Collect();
        }
    }
}
于 2014-06-15T18:06:17.957 に答える
10

または、短くて甘い Rx を使用します。

static void Main()
{
Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(t => Console.WriteLine("I am called... {0}", t));

for (; ; ) { }
}
于 2013-01-26T14:16:34.347 に答える
4

もう少し制御が必要な場合は、独自のタイミングメカニズムを使用することもできますが、精度が低くなり、コード/複雑さが増す可能性がありますが、それでもタイマーをお勧めします。ただし、実際のタイミング スレッドを制御する必要がある場合は、これを使用します。

private void ThreadLoop(object callback)
{
    while(true)
    {
        ((Delegate) callback).DynamicInvoke(null);
        Thread.Sleep(5000);
    }
}

あなたのタイミングスレッドになります(これを変更して、必要に応じて、必要な時間間隔で停止します)。

使用/開始するには、次のことができます。

Thread t = new Thread(new ParameterizedThreadStart(ThreadLoop));

t.Start((Action)CallBack);

Callback は、各間隔で呼び出すパラメーターなしの void メソッドです。例えば:

private void CallBack()
{
    //Do Something.
}
于 2008-10-09T06:29:10.660 に答える
2

独自のものを作成することもできます (利用可能なオプションに不満がある場合)。

独自の実装を作成するTimerことは、かなり基本的なことです。

これは、コードベースの残りの部分と同じスレッドで COM オブジェクト アクセスを必要とするアプリケーションの例です。

/// <summary>
/// Internal timer for window.setTimeout() and window.setInterval().
/// This is to ensure that async calls always run on the same thread.
/// </summary>
public class Timer : IDisposable {

    public void Tick()
    {
        if (Enabled && Environment.TickCount >= nextTick)
        {
            Callback.Invoke(this, null);
            nextTick = Environment.TickCount + Interval;
        }
    }

    private int nextTick = 0;

    public void Start()
    {
        this.Enabled = true;
        Interval = interval;
    }

    public void Stop()
    {
        this.Enabled = false;
    }

    public event EventHandler Callback;

    public bool Enabled = false;

    private int interval = 1000;

    public int Interval
    {
        get { return interval; }
        set { interval = value; nextTick = Environment.TickCount + interval; }
    }

    public void Dispose()
    {
        this.Callback = null;
        this.Stop();
    }

}

次のようにイベントを追加できます。

Timer timer = new Timer();
timer.Callback += delegate
{
    if (once) { timer.Enabled = false; }
    Callback.execute(callbackId, args);
};
timer.Enabled = true;
timer.Interval = ms;
timer.Start();
Window.timers.Add(Environment.TickCount, timer);

タイマーが機能することを確認するには、次のように無限ループを作成する必要があります。

while (true) {
     // Create a new list in case a new timer
     // is added/removed during a callback.
     foreach (Timer timer in new List<Timer>(timers.Values))
     {
         timer.Tick();
     }
}
于 2013-10-18T02:25:15.113 に答える
1

https://github.com/bigabdoul/PowerConsoleにある Github の PowerConsole プロジェクト、またはhttps://www.nuget.org/packages/PowerConsoleにある同等の NuGet パッケージを使用します。再利用可能な方法でタイマーをエレガントに処理します。このサンプル コードを見てください。

using PowerConsole;

namespace PowerConsoleTest
{
    class Program
    {
        static readonly SmartConsole MyConsole = SmartConsole.Default;

        static void Main()
        {
            RunTimers();
        }

        public static void RunTimers()
        {
            // CAUTION: SmartConsole is not thread safe!
            // Spawn multiple timers carefully when accessing
            // simultaneously members of the SmartConsole class.

            MyConsole.WriteInfo("\nWelcome to the Timers demo!\n")

            // SetTimeout is called only once after the provided delay and
            // is automatically removed by the TimerManager class
            .SetTimeout(e =>
            {
                // this action is called back after 5.5 seconds; the name
                // of the timer is useful should we want to clear it
                // before this action gets executed
                e.Console.Write("\n").WriteError("Time out occured after 5.5 seconds! " +
                    "Timer has been automatically disposed.\n");

                // the next statement will make the current instance of 
                // SmartConsole throw an exception on the next prompt attempt
                // e.Console.CancelRequested = true;

                // use 5500 or any other value not multiple of 1000 to 
                // reduce write collision risk with the next timer
            }, millisecondsDelay: 5500, name: "SampleTimeout")

            .SetInterval(e =>
            {
                if (e.Ticks == 1)
                {
                    e.Console.WriteLine();
                }

                e.Console.Write($"\rFirst timer tick: ", System.ConsoleColor.White)
                .WriteInfo(e.TicksToSecondsElapsed());

                if (e.Ticks > 4)
                {
                    // we could remove the previous timeout:
                    // e.Console.ClearTimeout("SampleTimeout");
                }

            }, millisecondsInterval: 1000, "EverySecond")

            // we can add as many timers as we want (or the computer's resources permit)
            .SetInterval(e =>
            {
                if (e.Ticks == 1 || e.Ticks == 3) // 1.5 or 4.5 seconds to avoid write collision
                {
                    e.Console.WriteSuccess("\nSecond timer is active...\n");
                }
                else if (e.Ticks == 5)
                {
                    e.Console.WriteWarning("\nSecond timer is disposing...\n");

                    // doesn't dispose the timer
                    // e.Timer.Stop();

                    // clean up if we no longer need it
                    e.DisposeTimer();
                }
                else
                {
                    System.Diagnostics.Trace.WriteLine($"Second timer tick: {e.Ticks}");
                }
            }, 1500)
            .Prompt("\nPress Enter to stop the timers: ")
            
            // makes sure that any remaining timer is disposed off
            .ClearTimers()

            .WriteSuccess("Timers cleared!\n");
        }
    }
}
于 2020-09-30T14:41:27.873 に答える
0

文書

そこにあります:)

public static void Main()
   {
      SetTimer();

      Console.WriteLine("\nPress the Enter key to exit the application...\n");
      Console.WriteLine("The application started at {0:HH:mm:ss.fff}", DateTime.Now);
      Console.ReadLine();
      aTimer.Stop();
      aTimer.Dispose();

      Console.WriteLine("Terminating the application...");
   }

   private static void SetTimer()
   {
        // Create a timer with a two second interval.
        aTimer = new System.Timers.Timer(2000);
        // Hook up the Elapsed event for the timer. 
        aTimer.Elapsed += OnTimedEvent;
        aTimer.AutoReset = true;
        aTimer.Enabled = true;
    }

    private static void OnTimedEvent(Object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
                          e.SignalTime);
    }
于 2019-12-13T15:12:45.900 に答える