2

HashSetがあります。場合によっては、このハッシュセットに新しい値が追加されます。私がやろうとしているのは、タイマーが追加されてからちょうど1分後にセットから各要素を削除することです。

私はまだrxを初めて使用しますが、これはそれを使用する理想的な機会のようです。

私はこのようなことを試みました:

AddItem(string item)
{
  _mySet.Add(item);
  var timer = Observable.Timer(TimeSpan.FromSeconds(60), _scheduler);
  timer
      .Take(1)
      .Do(item => RemoveItem(item))
      .Subscribe(_ => Console.WriteLine("Removed {0}", item));
}

正常に動作しているようです(単体テストに合格しています)。

誰かがこのアプローチに何か問題があると思いますか?

4

4 に答える 4

3
  1. 呼び出しのラムダはDo正しく見えませんObservable.Timer-int値を生成しますが、コレクションはHashSet<string>-コンパイルされるべきではありません。ただのタイプミスだったと思います。

  2. Do:通常、サブスクリプションはで行う必要がありますSubscribeDo副作用を対象としています(ストリーム内の副作用の概念が嫌いなので、回避しますが、デバッグには役立ちます)。

  3. TakeObservable.Timer終了する前に1つの値のみを生成するため、Take演算子は必要ありません

私はあなたの関数を次のように書きます:

AddItem(string item)
{
    _mySet.Add(item);
    Observable.Timer(TimeSpan.FromSeconds(60), _scheduler)
        .Subscribe(_ => RemoveItem(item));
}
于 2013-03-21T20:11:19.200 に答える
2

これを行うためにシーケンスを作成する必要はありません。あなたはすでに善良な市民であり、スケジューラーを明示的に使用しているので、それを使用してください!

あなたはあなたのコードのためにこれを持っていることができます

AddItem(string item)
{
  _mySet.Add(item);
  //Note this does return an IDisposable if you want to cancel the subscription.
  _scheduler.Schedule(
    TimeSpan.FromSeconds(60),
    ()=>
    { 
        RemoveItem(item);
        Console.WriteLine("Removed {0}", item);
    });
}

これは基本的に、内部で行われている作業がはるかに少ないことを意味します。Observable.Timerメソッドが実行しているすべての作業を検討してください。事実上、必要なのは、値(無視する)を使用してOnNextをスケジュールすることだけです。

また、Rxについて何も知らないユーザーでも、このスケジュールコードを読み取ることができると思います。すなわち。「このアイテムを追加した後、この削除アクションを60秒で実行するようにスケジュールします)。

于 2013-03-22T15:45:20.413 に答える
0

ReactiveUIを使用している場合ReactiveCollection、ここで呼び出されるクラスは間違いなく役立ちます。次のように使用できます。

theCollection.ItemsAdded
    .SelectMany(x => Observable.Timer(TimeSpan.FromSeconds(60), _scheduler).Select(_ => x))
    .Subscribe(x => theCollection.Remove(x));
于 2013-03-21T20:06:11.940 に答える
-3

申し訳ありませんが、あなたを選ぶつもりはありませんが、:

常にIDISPOSABLESを処分してください!!!!!

(編集:わかりました、今朝コーヒーに何を入れたかはわかりませんが、私はナンセンスの全体の混乱で答えました;一般的に、あなたは必ず処分したいので、上記を残しますIDisposableが、次のせせらぎを補うために...)

を呼び出すとSubscribe、破棄しないサブスクリプションが作成されるため、このメソッドを複数回呼び出すと、ますます多くのがらくたがキューに入れられます。この特定のケースでは、Timer1回だけ起動するため、世界の終わりではありませんが、それでも...廃棄!

この方法を本当に使用したい場合(より良いアプローチは、値に「傾向がある」実行中のスレッド/タスクを用意し、必要と思われるときに削除することです)、少なくとも次のようなものを試してください。

わかりました、すべての打ちのめされたがらくたを無視します。の実装Observable.Timerは次のとおりです。

public static IObservable<long> Timer(TimeSpan dueTime)
{
    return s_impl.Timer(dueTime);
}

これは順番にこれを呼び出します:

public virtual IObservable<long> Timer(TimeSpan dueTime)
{
    return Timer_(dueTime, SchedulerDefaults.TimeBasedOperations);
}

呼び出す...

private static IObservable<long> Timer_(TimeSpan dueTime, IScheduler scheduler)
{
    return new Timer(dueTime, null, scheduler);
}

そして、ここで物事が楽しくなります-TimerProducer<long>、肉の部分があります:

private IDisposable InvokeStart(IScheduler self, object state)
{
    this._pendingTickCount = 1;
    SingleAssignmentDisposable disposable = new SingleAssignmentDisposable();
    this._periodic = disposable;
    disposable.Disposable = self.SchedulePeriodic<long>(1L, this._period, new Func<long, long>(this.Tock));
    try
    {
        base._observer.OnNext(0L);
    }
    catch (Exception exception)
    {
        disposable.Dispose();
        exception.Throw();
    }
    if (Interlocked.Decrement(ref this._pendingTickCount) > 0)
    {
        SingleAssignmentDisposable disposable2 = new SingleAssignmentDisposable {
            Disposable = self.Schedule<long>(1L, new Action<long, Action<long>>(this.CatchUp))
        };
        return new CompositeDisposable(2) { disposable, disposable2 };
    }
    return disposable;
}

さて、これbase._observer.OnNextはタイマーティックでトリガーするように設定された内部シンクです。ここで、Invokeは次のとおりです。

private void Invoke()
{
    base._observer.OnNext(0L);
    base._observer.OnCompleted();
    base.Dispose();
}

あ、はい。それはそれ自体を自動処理します-そして「長引くサブスクリプション」が浮かんでいることはありません。

うーん……カラスが美味しいです。:|

于 2013-03-21T16:25:43.413 に答える