C# Rx延迟控制器扩展实现
我正在尝试在C#中实现bool值的扩展。实现应该直接传递假值,但当接收到真值时,它应该延迟输出带有前缀延迟的真值 大理石图应为:C# Rx延迟控制器扩展实现,c#,extension-methods,system.reactive,C#,Extension Methods,System.reactive,我正在尝试在C#中实现bool值的扩展。实现应该直接传递假值,但当接收到真值时,它应该延迟输出带有前缀延迟的真值 大理石图应为: |Delay| |Delay| F---T---F---T----T---T---F---C -F-----------------T------F---C 注: 它应该包含不同的值(或不包含) 仅当源中的真值至少延迟了一段时间时,它才应输出真值 如果输出中有一组真值,则使用第一个值计算延迟 当源发出false时,应立即传递到输出 我目前的实
|Delay| |Delay|
F---T---F---T----T---T---F---C
-F-----------------T------F---C
注:
- 它应该包含不同的值(或不包含)
- 仅当源中的真值至少延迟了一段时间时,它才应输出真值
- 如果输出中有一组真值,则使用第一个值计算延迟
- 当源发出false时,应立即传递到输出
公共静态IObservable ThrottleOnTrue(此IObservable源,时间跨度延迟)
{
返回source.DistinctUntilChanged()。选择(值=>value
?可观察的。从不()。开始(真)。延迟(延迟)
:可观察。从不().StartWith(false))
.开关();
}
但似乎不起作用,因为之后的真值没有正确地取消,之后的假值。我是Rx的新手,所以可能有更好的方法来实现这个扩展
这将用于检查多个服务器应用程序的IObservable CanProcessMoreJobs属性,在快速输出更改后,只向服务器添加更多作业,且至少具有延迟值的真值。这是一个有趣的问题,我确实想知道这是否可能是一种问题。无论如何,考虑到您的大理石图,您几乎肯定不需要一个
DistinctUntilChanged()
,否则您将永远不会得到重复的“F”
我的方法(当然还有其他方法)是安排所需的输出,确保删除任何“节流”的值(即在延迟期内T后跟F)。这可以通过以下方式实现:
public static IObservable<bool> ThrottleOnTrue(this IObservable<bool> source, TimeSpan delay) =>
source
.Select(value =>
Observable
.Return(value)
.Delay(value ? delay : TimeSpan.Zero))
.Switch();
public static IObservable ThrottleOnTrue(此IObservable源、TimeSpan延迟、isScheduler调度程序)
{
返回可观察的。创建(
观察员=>
{
var serialDisposable=新的serialDisposable();
var延迟=源
.具体化
.扫描(
(通知:(通知)无效,延迟:0L),
(种子,源)=>source.Kind开关
{
NotificationKind.OnCompleted=>(Notification.CreateOnCompleted(),seed.Delay),
NotificationKind.OneError=>(Notification.createOneError(source.Exception),0),
_=>source.Value
?(Notification.CreateOnNext(source.Value),delay.Ticks+1)
:(Notification.CreateOnNext(source.Value),1)
})
.Where(tuple=>tuple.Notification!=null)
.Publish();
//在延迟后发出值,取消受限制的项
var onNext=延迟
.Where(tuple=>tuple.Notification.Kind==NotificationKind.OnNext)
.Subscribe(tuple=>serialDisposable.Disposable=scheduler.Schedule(scheduler.Now.AddTicks(tuple.Delay),()=>observer.OnNext(tuple.Notification.Value));
//在最后一个要发射的项目延迟后发射完成
var onCompleted=延迟
.Where(tuple=>tuple.Notification.Kind==NotificationKind.OnCompleted)
.Subscribe(tuple=>scheduler.Schedule(scheduler.Now.AddTicks(tuple.Delay),()=>observer.OnCompleted());
//立即发出错误,取消所有挂起的项
var onError=延迟
.Where(tuple=>tuple.Notification.Kind==NotificationKind.OnError)
.Subscribe(tuple=>serialDisposable.Disposable=scheduler.Schedule(TimeSpan.Zero,()=>observer.OnError(tuple.Notification.Exception));
返回新的CompositeDisposable(新的IDisposable[]{onNext,onCompleted,onError,delays.Connect(),serialDisposable});
}
);
}
它看起来有点复杂,因为需要在之前延迟的项(我们使用Scan
tuple跟踪)之后处理完成
无论如何,请注意添加了调度程序
参数。在向Rx添加任何形式的异步时,应始终提供一个参数,但可以默认设置为调度程序。默认设置为,如下所示:
公共静态IObservable ThrottleOnTrue(此IObservable源,时间跨度延迟)
{
返回source.ThrottleOnTrue(delay,Scheduler.Default);
}
现在,ThrottleOnTrue可以通过使用的“虚拟时间”显示工作(使用稍微不同的大理石图)。这里有一个测试显示“F”值会立即发出(当前时间+1勾用于调度):
private static long SchedulerOffset=ReactiveTest.Created+ReactiveTest.Subscribed;
私有静态长通知偏移量=ReactiveTest.Subscribed;
///
///来源:F--F--F-C
///预期:-F---F---F-C
///
[测试]
public void应直接传递FalseValues()
{
var scheduler=newtestscheduler();
var source=new[]
{
新录制的(TimeSpan.FromSeconds(1).Ticks,Notification.CreateOnNext(false)),
新录制的(TimeSpan.FromSeconds(2).Ticks,Notification.CreateOnNext(false)),
新录制的(TimeSpan.FromSeconds(3).Ticks,Notification.CreateOnNext(false)),
新录制(TimeSpan.FromSeconds(3).Ticks+1,Notification.CreateOnCompleted())
};
预期风险值=新[]
{
新录制的(TimeSpan.FromSeconds(1).Ticks+NotificationOffset+1,Notification.CreateOnNext(false)),
新录制的(TimeSpan.FromSeconds(2).Ticks+NotificationOffset+1,Notification.CreateOnNext(false)),
新录制的(TimeSpan.FromSeconds(3).Ticks+NotificationOffset+1,Notification.CreateOnNext(false)),
新录制(时间跨度从秒(3)开始)。滴答声
2020/06/15 01:16:23 +00:00 False
2020/06/15 01:16:31 +00:00 False
2020/06/15 01:16:40 +00:00 True
2020/06/15 01:16:48 +00:00 False
public static IObservable<bool> ThrottleOnTrue(this IObservable<bool> source, TimeSpan delay) =>
source
.Select(value =>
Observable
.Return(value)
.Delay(value ? delay : TimeSpan.Zero))
.Switch();