我有一个HashSet。 Occasionlay,新值将添加到此哈希集。我要做的是让计时器在添加后的一分钟内从集合中删除每个元素。
我还是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));
}
似乎工作正常(通过单元测试)。
有人看到这种方法有什么问题吗?
答案 0 :(得分:3)
Do
调用中的lambda看起来不正确 - Observable.Timer
生成int值,但您的集合是HashSet<string>
- 这不应该编译。我猜这只是一个错字。
Do
:一般来说,您的订阅应该在Subscribe
中完成。 Do
用于副作用(我不喜欢流中副作用的想法,所以我避免它,但它对调试很有用)。
Take
:Observable.Timer
在终止前只生成一个值,因此不需要Take
运算符
我会把你的功能写成:
AddItem(string item)
{
_mySet.Add(item);
Observable.Timer(TimeSpan.FromSeconds(60), _scheduler)
.Subscribe(_ => RemoveItem(item));
}
答案 1 :(得分:2)
您不需要创建序列来执行此操作。你已经是一个好公民并使用Scheduler明确,所以只需使用它!
你可以为你的代码提供这个
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秒内运行。”
答案 2 :(得分:0)
如果您使用的是ReactiveUI,那么名为ReactiveCollection
的类肯定会对您有所帮助,您可以像这样使用它:
theCollection.ItemsAdded
.SelectMany(x => Observable.Timer(TimeSpan.FromSeconds(60), _scheduler).Select(_ => x))
.Subscribe(x => theCollection.Remove(x));
答案 3 :(得分:-2)
对不起,不是故意选择你,而是:
始终禁止IDISPOSABLES !!!!!
(编辑:好的,不知道我今天早上放在咖啡里的是什么,但我回答的是一堆乱七八糟的废话;我会留下上面只是因为一般,你我想确保处置任何IDisposable
,但是为了弥补随后的喋喋不休......)
<击>
对Subscribe
的调用创建了一个你没有处理的订阅,所以对这个方法的多次调用只会排队越来越多的垃圾 - 现在在这个特定情况下,它不是自{{ {1}}只发射一次,但仍然......处理!
如果你真的想要使用这种方法(我认为更好的方法是让一些正在运行的线程/任务“倾向于”你的价值观,在它认为必要时删除),至少尝试类似于:
击>
好的,忽略所有那些被淘汰的垃圾。 Timer
的实施是这样的:
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);
}
是一个Timer
,其中的内容是:
Producer<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
是的。它自动处理 - 并且不会有任何“挥之不去的订阅”。
嗯......乌鸦很好吃。 :|