C# 无功扩展定时器
我有一个哈希集。Occasionlay,新值将添加到此哈希集。我想做的是让一个计时器在添加元素一分钟后将其从集合中移除 我仍然是新的接收,但这似乎是一个理想的场合使用它 我试过这样的方法:C# 无功扩展定时器,c#,system.reactive,C#,System.reactive,我有一个哈希集。Occasionlay,新值将添加到此哈希集。我想做的是让一个计时器在添加元素一分钟后将其从集合中移除 我仍然是新的接收,但这似乎是一个理想的场合使用它 我试过这样的方法: AddItem(string item) { _mySet.Add(item); var timer = Observable.Timer(TimeSpan.FromSeconds(60), _scheduler); timer .Take(1) .Do(item =>
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));
}
theCollection.ItemsAdded
.SelectMany(x => Observable.Timer(TimeSpan.FromSeconds(60), _scheduler).Select(_ => x))
.Subscribe(x => theCollection.Remove(x));
它似乎工作正常(通过了单元测试)
有人认为这种方法有什么不对吗?对不起,我不是故意挑你的毛病,但是: 始终处理IDispobles强> (编辑:好吧,我不知道今天早上我在咖啡里放了什么,但我的回答完全是胡说八道;我只留下上面的内容,因为一般来说,你确实想确保处理掉任何
IDisposable
,但为了弥补接下来的唠叨……)
对Subscribe
的调用创建了一个您没有处理的订阅,因此对该方法的多次调用只会让越来越多的垃圾排队-现在在这种特定情况下,这不是世界末日,因为计时器只触发一次,但仍然…Dispose
如果您真的想使用这种方法(我认为更好的方法是让一些正在运行的线程/任务“倾向于”您的值,在认为必要时删除),至少可以尝试以下类似的方法:
好吧,不要理会那些被剔除的废话。可观察计时器的实现如下:
public static IObservable<long> Timer(TimeSpan dueTime)
{
return s_impl.Timer(dueTime);
}
现在是base.\u observer.OnNext
,这是设置为在计时器滴答声时触发的内部接收器,其中的调用
,即:
private void Invoke()
{
base._observer.OnNext(0L);
base._observer.OnCompleted();
base.Dispose();
}
所以是的。它会自动处理自己——而且不会有任何“延迟订阅”四处浮动
嗯……乌鸦很好吃| 如果您使用的是ReactiveUI,那么一个名为ReactiveCollection
的类肯定会有帮助,您可以这样使用它:
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));
}
theCollection.ItemsAdded
.SelectMany(x => Observable.Timer(TimeSpan.FromSeconds(60), _scheduler).Select(_ => x))
.Subscribe(x => theCollection.Remove(x));
Do
调用中的lambda看起来不正确-可观察。计时器
生成int值,但您的集合是一个哈希集
-这不应该编译。我猜这只是个打字错误
Do
:通常,您的订阅应该在Subscribe
中完成Do
是针对副作用的(我不喜欢流中的副作用,所以我避免它,但它对调试很有用)
Take
:可观察。计时器在终止之前只产生一个值,因此不需要Take
运算符
我将把你的函数写成:
AddItem(string item)
{
_mySet.Add(item);
Observable.Timer(TimeSpan.FromSeconds(60), _scheduler)
.Subscribe(_ => RemoveItem(item));
}
这样做不需要创建序列。你已经是一个好公民,并且明确地使用了调度器,所以就使用它吧
你可以把它作为你的代码
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);
});
}
这基本上意味着在幕后进行的工作要少得多。考虑所有可观察到的工作。计时器方法正在进行,当你只想让它做的是用一个值(你忽略)来调度一个ONNEXT。
我还假设,即使是一个对Rx一无所知的用户也能够阅读此计划代码。ie.“添加此项目后,我计划在60秒内运行此删除操作)。嘿,杰克林巴勒,我认为在采取(1)之后满足后,源将自动释放。如果我添加一个未完成的处理程序,我会看到它被调用。调用未完成时,源是否已释放?@JerKimbal,这是错误的建议,请将其删除。在Rx上下文中IDisposable不需要处理。在Rx中,释放具有特殊含义,即提前断开订阅。没有内存泄漏,示例代码没有问题。抱歉@JerKimball,您通常对Rx很在行,但Paul和Flack是正确的-一旦序列完成,订阅将自动“处理”(取消订阅).哦,天哪,我真的很抱歉;我不知道我到底在想什么…你当然是对的-让我看看我是否可以通过一些编辑在这里重新获得一些面子…*facepalm*@AlexG我的羞耻感很好。我把这归咎于严重的头痛和最近的调试深入地狱。)哈哈。我只是指出,这与q中的代码实现了相同的结果问题不是问他如何切换到一个新的库并“更具功能”。正如Flack在问题中指出的,原始代码可以工作并通过单元测试。我只是建议他不需要使用序列。你认为AddItem(“foo”);会有什么样的行为……30秒后AddItem(“foo”)?
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);
});
}