0

私はC#にまったく慣れていないので、この質問の無知を許してください。しかし、一時変数または時限変数の設定と処理についてはどうすればよいでしょうか。たとえば、イベントが発生するたびに、カウンターをインクリメントしたいと思います。60秒以内にカウンターが3を超えた場合、別のイベントをトリガーしたいと思います。それ以外の場合、60秒が経過してもカウンターがインクリメントされない場合は、0にリセットされます。

MemoryCacheを使用する必要がありますか?または、指定された期間の後に変数を設定解除するために変数に設定できる気の利いたフラグがありますか(更新されていない場合)?この単純なタスクを実行するための最良の方法は何でしょうか?私は必ずしも私のためにそれを書く誰かを探しているわけではないことに注意してください。私を正しい方向に向けるための役に立つ手や提案です。これは私が達成しようとしていることの大まかな概要です:

private static int totalCount = 0;
private static double maxCount = 3;
private static double timeLimit = 60;

private static void TestEvent(object src, EventArgs mea)
{
  totalCount++;
  if (totalCount > maxCount)
  {
    DoSomething();
  }
}

あなたが提供できるどんな援助にも感謝します。私は常に役立つ答えに報いることを重要視しています。

4

6 に答える 6

4

Queue<T>http://msdn.microsoft.com/en-us/library/7977ey2c.aspxを参照)を維持できます。各エントリは、イベントが発生した時刻です。イベントが発生すると、最初に60秒以上前のエントリをキューから削除し(キューは時間順に並べられ、キューの先頭が最も古いエントリであるため、簡単です)、次に新しいエントリを追加します。ちょうど発砲したイベントのために。キューの数がしきい値を超えている場合は、探している条件を満たしています。

に保存する時間のDateTime.UtcNow代わりに使用することをお勧めします。UtcNowははるかに高速であり、夏時間から標準時間への移行、およびその逆の移行によって発生する可能性のある問題を回避します。DateTime.NowQueue<T>

これが私の頭のてっぺんからのコードです(少し修正が必要かもしれません):

private static Queue<DateTime> eventQueue = new Queue<DateTime>();
private static int timeWindowSeconds = 60;
private static int threshold = 3;

private static void TestEvent(object src, EventArgs mea) {
    DateTime now = DateTime.UtcNow;
    DateTime tooOld = now.AddSeconds(-timeWindowSeconds);

    // remove old entries
    while((eventQueue.Count > 0) && (eventQueue.Peek() < tooOld)) {
        eventQueue.Dequeue();
    }

    // add new entry
    eventQueue.Enqueue(now);

    // test for condition
    if (eventQueue.Count >= threshold) {
        eventQueue.Clear();
        DoSomething();           
    }
}
于 2012-09-14T20:07:26.600 に答える
2

あなたはこのようにするかもしれません:

private static int totalCount = 0;
private static double maxCount = 3;
private static TimeSpan timeLimit = TimeSpan.FromSeconds(60);
private static DateTime lastIncrementTime;

private static void TestEvent(object src, EventArgs mea)
{
    // If the time between now and lastIncrementTime is more than the timeLimit...
    if(DateTime.Now - lastIncrementTime > timeLimit)
    {
        totalCount = 0;
    }
    lastIncrementTime = DateTime.Now;

    totalCount++;     
    if (totalCount > maxCount)
    {
        DoSomething();
    }
}
于 2012-09-14T19:55:32.697 に答える
1

StopWatchクラスを使用できます。

フォームの読み込みイベント(そのイベントから60秒をカウントする場合)で、タイマーを開始します。クリックイベントで毎回、他のメソッドなどで呼び出される秒数を確認します。

于 2012-09-14T20:07:37.627 に答える
1

別の変数を使用して、の値を変更した時間をログに記録できますtotalcount。現在の時刻で確認し、好きなことをしてください。
これがコードです...

private static int totalCount = 0;
private static double maxCount = 3;
private static double timeLimit = 60;
private static DateTime  timeflag= DateTime.Now;

private static void TestEvent(object src, EventArgs mea)
{
    if (timeflag.AddSeconds(timeLimit) < DateTime.Now)
    {
        totalCount = 0;
    }
    totalCount++;
    timeflag = DateTime.Now;
    if (totalCount > maxCount)
    {
            DoSomething();
    }
}
于 2012-09-14T19:53:21.353 に答える
1

これにアプローチできる方法は無数にあります。私が最初に頭に浮かぶのは、バックグラウンドスレッドで開始するStopwatchオブジェクトまたはTimerオブジェクトを使用してから、関心のあるイベントをサブスクライブできるイベントハンドラーを作成することです。イベントが発生すると、ハンドラーが起動し、タイマーを一時停止して経過時間を照会し、それに応じて増分/リセットの決定を行うことができます。

これは、1つの概念の非常に大まかなスケッチにすぎませんが、前進するためのいくつかのアイデアを提供するはずです。幸運を。

上記の@hatchetによるコメントによると、これは、コメントが問題を正確に反映している場合にキャプチャする必要がある「期限切れ」メンバーまたは「スライディングウィンドウ」イベントホライズンのキューのように聞こえ始めます。

編集私は境界線の強迫神経症なので、あなたの元の問題にいくつかの考えを与え、あなたの問題に関連するかもしれないし、関連しないかもしれない概念を思いつきました、しかし少なくとも学術演習のために私は私が何を投稿するつもりですやりました。あなたの元の投稿で私の注意を引いたのは、非常に斬新だと思った、期限切れまたは時限変数の概念でした。あなたの問題は、与えられた間隔が経過したときに特定のことをしたいということを指定しました。

私はそのアイデアを一般的な形に抽象化しようとしました。そのようなアイデアが役立つかもしれないいくつかの方法を考えました。頭に浮かんだアイデアの1つは、ゲーム環境でした。たとえば、メッセージは、「自己破壊」する前の20秒間だけプレーヤーが利用できる場合があります。有効期限の「配管」をタイプに配線することが非常に便利であることがどのように証明されるか想像できました。別のシナリオは、System.Drawing.Imageが一定時間だけ表示されてから消えるCAI環境である可能性があります。これも、有効期限とタイミングコードが組み込まれているシナリオが役立つ場合があります。

したがって、少なくともその多くの概念的な実用性を念頭に置いて、私は仕事に取り掛かりました。私が一緒に投げたもの(そして私はその包括的または完全なふりをしません)は、で表される期限切れタイプのジェネリックですExpiring<T>。私がまとめたベースラインコードは次のとおりです。

    // First stab at an "expiring" type that is only valid for a set interval.
public class Expiring<T>
{
    public delegate void ExpiredHandler(object sender, EventArgs e);
    public event ExpiredHandler OnExpired;

    T instance;
    int signaledCount = 0;
    long milliseconds = 0;
    bool isExpired = false;
    bool exceptOnExpiredReference = true;
    System.Timers.Timer lapseTimer = new System.Timers.Timer();

    public Expiring(T value)
    {
        instance = value;
    }

    public virtual void TimerElapsed(object sender, System.Timers.ElapsedEventArgs args)
    {
        if (OnExpired != null)
        {
            OnExpired(this, null);
        }

        isExpired = true;
    }

    public Expiring(T startValue, long expirationInterval, bool throwElapsedReferenceException):this(startValue)
    {
        milliseconds = expirationInterval;
        lapseTimer.AutoReset = true;
        lapseTimer.Interval = milliseconds;
        exceptOnExpiredReference = throwElapsedReferenceException;
        lapseTimer.Elapsed+=new System.Timers.ElapsedEventHandler(TimerElapsed);
        this.Set();

    }


    public void Set()
    {
        signaledCount++;
        lapseTimer.Stop();
        lapseTimer.Start();
    }

    public T Value
    {
        get
        {
            if (!isExpired || !exceptOnExpiredReference)
                return instance;
            else
                throw new InvalidOperationException("Reference to an expired value.");
        }
        set
        {
            instance = value;
        }
    }
}

ここでの考え方は、誰かがを宣言しExpiring<int>、その初期値、有効期限、および有効期限が経過した後にインスタンスの値にアクセスしようとして例外をスローするかどうかを示す値を指定できるということです。ExpirationIntervalが経過すると、OnExpiredイベントが発生し、宣言者がカスタムイベントハンドラーを指定して、値の有効期限が切れたときにカスタムアクションを提供できるようになります。

呼び出し元が有効期限タイマーをリセットしたい場合は、オブジェクトのSet()メソッドを呼び出すだけで済みます。これはまた、私が最終的に使用しなかった内部の「signaledCount」値をインクリメントしますが、有効期限タイマーがリセットされた回数を決定するという観点から考えていました。有効期限が経過した後にオブジェクトのValueプロパティにアクセスすると、InvalidOperationExceptionがスローされ、「Valuehasexpired」メッセージが表示されます。

残念ながら、このアイデアは実用的というよりも概念的/学術的価値があります。すべての算術演算子をネイティブ値型の実装にオーバーロードすることができれば、はるかに多くの有用性がありますが、C#がこの概念をまったく好まないことをすぐに発見しました(そして、ここでそれを見つけましたここSOの主題に関するかなり広範な投稿)。理想的には、次のようなことを言えるようにしたいと思います。

Expired<Int32> foo = new Expired<Int32>(5,10000,true);
Expired<Int32> bar = new Expired<Int32>(10,10000,true);
Expired<Int32> baz = foo+bar;  // can't make that work

この問題は動的型で克服できるという考えもありましたが、現時点では追求しないことにしました。私が打ち出したアイデアは、OPの「時限変数」の概念の一般的な見方に適用されるため、議論のために提供されています。建設的なコメント/批評/洗練が奨励され、歓迎されます。

于 2012-09-14T19:55:24.347 に答える
1

私はこのようなことをします:

private class SomeEventMonitor
{
    public  int      Threshold       { get ; private set ; }
    public  TimeSpan ThresholdWindow { get ; private set ; }

    private DateTime  marker ;
    private int       count  ;

    /// <summary>
    /// public constructor
    /// </summary>
    /// <param name="threshold"></param>
    /// <param name="window"></param>
    public SomeEventMonitor( int threshold , TimeSpan window )
    {
        if ( threshold <  1             ) throw new ArgumentOutOfRangeException("threshold") ;
        if ( window    <= TimeSpan.Zero ) throw new ArgumentOutofRangeException("window") ;

        this.Threshold       = threshold ;
        this.ThresholdWindow = window    ;

        Reset() ;

        return ;
    }

    private void Reset()
    {
        this.marker       = DateTime.Now ;
        this.count        = 0            ;
        return ;
    }

    public event EventHandler ThresholdExceeded ;

    private static readonly object latch = new object() ;
    public void EventWatcher( object source , EventArgs eventArgs )
    {
        lock ( latch )
        {
            DateTime current = DateTime.Now ;

            if ( ++count > Threshold )
            {
                TimeSpan window = current -marker ;
                if ( window > ThresholdWindow )
                {
                    ThresholdExceeded( this , new EventArgs() ) ;
                    Reset() ;
                }
            }

        }
        return ;
    }

}
于 2012-09-14T21:01:36.210 に答える