2012-05-10 13 views
2

私は毎秒1回実行する関数OnCreate()を持っています。 OnCreateは、現在の時刻(現在の秒)に基づいて他の機能を呼び出します。しかし、個々の関数をそれぞれOnCreateの中に個別に書き込むのではなく、関数をグループ化することができるようにしたいと考えています。つまり、の10秒後に関数CreateFiveXを呼び出して、新しい秒ごとに5秒間行う。その後、20秒のマークで、私はOnCreateが同じ機能を再び呼びたいと思っています。C#時間に基づくカスタムイベント

私はイベントとデリゲートを使用してこの問題を解決したいと思います。私はOnCreateの開始時に、現在の時刻をとり、それをすべての加入者に送信するイベントを発生させたいと考えています。購読リスト。

問題はあまりにも多くの時間が経過してもこれを行う方法を理解できず、さらに難しくするために、OnCreateが呼び出す関数に余分なパラメータを渡したいと思います。任意のすべての助けがいいです、ありがとう。

+1

正確に何をしますか? 'CreateFiveX()'を10秒ごとに呼び出しますか?それはどのように "機能をまとめてグループ化"していますか? – svick

+0

OnCreate()の内部if(timer == 10)CreateFiveX(); if(timer == 20)CreateFiveX();したがって、Xは2番目の10,11,12,13,14,20,21,22,23、および24に作成されます。したがって、基本的にCreateFiveX()は5つの関数(すべて同じ関数、わずか5回)を追加しますイベントすなわちタイマ== 21,22,23、および24でそれぞれ発動される。 – ryanb9

+0

あなたの快適さのレベルにもよりますが、このタイプの時間ベースの構成では、通常、Reactive Extensionsを使用します –

答えて

1

必要な間隔ごとに複数のタイマーを作成できます。またはOnCreate()は、システム時刻を確認してMath.Mod()を実行し、出力を特定の時刻に正しい機能を呼び出すswitchステートメントに入れることができます。いくつかのサンプルコードが必要な場合、私はあなたのためにいくつかを書くことができます。

+0

ありがとうございます。問題を解決するには、イベントと代理人を使用しますどのように考え出すことはできません。 – ryanb9

1

イベントを使用してコードのサンプル、およびパラメータ化ハンドラ:

public class TheTimer 
{ 
    // define delegate with desired parameters 
    public delegate void TimerDelegate(int param1, string param2); 

    // expose the event 
    public event TimerDelegate OnTimer; 

    // This is the handler of a regular Timer tick:or your OnCreate() function 
    Timer1_Tick() 
    { 
     if (OnTimer != null) // if susbcribed handlers 
     { 
      OnTimer(1, "value"); // raise your cutom event, passing the params 
     } 
    } 
} 

// Implement classes with functions that can handle the event 
public class HandlerFunctions 
{ 
    public void HandleTimer(int p, string p2) 
    { 
     // do whatever 
    } 
} 

// Use your classes 
public class TimerUserClass 
{ 
    public static void UseTimers() 
    { 
     // Create objects 
     TheTimer theTimer = new TheTimer(); 
     HandlerFunctions handler1 = new HandlerFunctions(); 
     HandlerFunctions handler2 = new HandlerFunctions(); 
     // SUbscribe events 
     theTimer.OnTimer += handler1.HandleTimer; 
     theTimer.OnTimer += handler2.HandleTimer; 
     // un-susbcribe 
     theTimer.OnTimer -= handler1.HandleTimer; 
    } 
} 
1

あなたのロジックはあなたの代わりにステートマシンの実装を検討する必要がありますとなりどのように複雑な依存。

machine.Every(new TimeSpan(hours: 0, minutes:0, seconds:5), eScheduledCheck); 

をそれとも、.Atメソッドを使用して行の5つのイベントをスケジュールすることができます:あなたは、たとえば、言うことができるので、私のown state machineは一時的なイベントを実装します。

毎秒Tick()メソッドを呼び出すだけで、必要に応じてステートマシンが前進するか、次回のアクションが必要であることを示すときにスリープまたはタイマーを設定することができます。

スケジュールされたイベントをキャンセルするために他のトリガーをプログラムする必要がある場合は、新しいイベントをスケジュールするか、通常の状態マシンのように振る舞います。また、階層的な状態もサポートしています。

状態を保存して再開する必要があり、スケジュールされたすべてのイベントが通常どおり実行される必要がある場合は、そのシナリオ用にも設計されています(たとえば、再起動後も存続する必要のあるNTサービス)。

Nugetからソースコードを入手できます。

1

これは興味深い質問だと思っていました。毎秒実行する関数についてのあなたの説明をよく理解していませんが、5秒間実行する別の関数を呼び出すと、メソッド呼び出しをカプセル化する方法です。だから私は、タイマーとActionデリゲートを使用するこのサンプルをあらかじめ決められたタイマーティックで呼び出す。あなたが探しているものなら、これをあなたのデザインに推論することができます。

class TimedFunction 
{ 
    public Action<TimedFunction, object> Method; 
    public int Seconds = 0; 

    public TimedFunction() { 
    } 

} 

class Program 
{ 

    static int _secondsElapsed = 0; 
    static List<TimedFunction> _funcs = new List<TimedFunction>(); 
    static int _highestElapsed = 0; 
    static Timer _timer; 

    static void Main(string[] args) { 

     var method = new Action<TimedFunction, object>((tf, arg) => Console.WriteLine("{0}: {1}", tf.Seconds, arg)); 

     _funcs.Add(new TimedFunction() { Seconds = 5, Method = method }); 
     _funcs.Add(new TimedFunction() { Seconds = 8, Method = method }); 
     _funcs.Add(new TimedFunction() { Seconds = 13, Method = method }); 
     _funcs.Add(new TimedFunction() { Seconds = 10, Method = method }); 

     _highestElapsed = _funcs.Max(tf => tf.Seconds); 

     _timer = new Timer(1000); 
     _timer.Elapsed += new ElapsedEventHandler(t_Elapsed); 
     _timer.Start(); 

     Console.WriteLine(); 
     Console.WriteLine("----------------------"); 
     Console.WriteLine("Hit any key to exit"); 
     Console.ReadKey(true); 
    } 

    static void t_Elapsed(object sender, ElapsedEventArgs e) { 
     _secondsElapsed++; 
     foreach (TimedFunction tf in _funcs) { 
      if (tf.Seconds == _secondsElapsed) { 
       tf.Method(tf, DateTime.Now.Ticks); 
      } 
     } 

     if (_secondsElapsed > _highestElapsed) { 
      Console.WriteLine("Finished at {0} seconds", _secondsElapsed - 1); 
      _timer.Stop(); 
     } 
    } 
} 

これが出力されます。

---------------------- 
Hit any key to exit 
5: 634722692898378113 
8: 634722692928801155 
10: 634722692949083183 
13: 634722692979496224 
Finished at 13 seconds 

(コンソールはキー入力を待っている間にタイマーがまだ実行されているので、これは動作します)

注私は同じActionデリゲートを使用しながら、ということすべてのTimedFunctionオブジェクトのインスタンスでは、異なるオブジェクトを使用することはできません。デリゲートが取る引数のタイプを定義する必要がありますが、いつでもobjectまたはその他のタイプを使用して、必要なものを渡すことができます。

また、エラーチェックもなく、このタイプのアプリケーションについては言及していません。たとえば、別のスレッドを使用したいとします。ああ、タイマーの解像度は本当に良くないので注意してください。

これが役に立ちます。

3

おそらくreinvent the reactive wheelをお試しになりましたか?

あなたがスコープ内に反応性の拡張機能がインストールおよび参照され、これらの名前空間を持っていることを確認してください:

System.Reactive 
System.Reactive.Linq 

その後、あなたは以下のコンビネータが一緒に参加しました(一例として)使用することができます。

  • Observable.Interval(timespan)毎にイベントを作成するtimespan
  • Observable.Take(number)は、今から、オフセットは特定の時間または時間に単一のイベントを作成するために、特定のnumber
  • Observable.Timer()のもの(または他のイベント)を制限または将来/過去の時刻に
  • Observable.Do(action)Observable.Subscribe(action)副作用または
  • Observable.Repeat(number)
  • 回数の上のいずれかを繰り返すストリームに基づいて、アクションの他のタイプを実行する
  • Observable.Generate()は状態

そしてcreate observables from enumerablesまたはevent patterns、およびmany many moreのようなものからのものも含め、その後多くの人から観察可能なシーケンスを生成します。

具体的な例がある場合は、Rxを使用してそれを行う方法を示します。 the relevant section of StackOverflowを参照することもできます。

+0

はい、私は再発明しようとしているか、少なくとも再考する方法を学んでいます。おかげさまで、他のすべてのポスターに感謝します。私は皆の提案に浸っています。編集:私は物事がどのように行われているかを学ぶほど多くを再考しようとしていませんxD簡単な方法はスレッドを作って5秒間ループしている間に1秒待つだけですが、問題。 – ryanb9

+0

これは複雑な領域です。 Rxを学習することは、最初からやり直すのではなく、挑戦的で充分な報酬です。あなたが学び、非常に便利なツールを持っているこの方法。 – yamen

関連する問題