Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# .NET ReactiveExtensions:将Sample()与变量timespan一起使用_C#_System.reactive_Rx.net - Fatal编程技术网

C# .NET ReactiveExtensions:将Sample()与变量timespan一起使用

C# .NET ReactiveExtensions:将Sample()与变量timespan一起使用,c#,system.reactive,rx.net,C#,System.reactive,Rx.net,给定一个高频可观察的数据流,我只想每XX秒发射一个项目 这通常在RX中通过使用.Sample(TimeSpan.FromSeconds(XX))完成 然而。。。我希望时间间隔根据数据的某些属性而变化 假设我的数据是: 阶级地位 { ... 公共交通速度; } 如果速度小于100,我希望每5秒发出一次数据。如果速度高于100,则应每2秒一次 使用现成的示例()可以这样做吗?或者我需要自己构建一些东西吗?让我知道这是否有效: var query = source .Publi

给定一个高频可观察的数据流,我只想每XX秒发射一个项目

这通常在RX中通过使用.Sample(TimeSpan.FromSeconds(XX))完成

然而。。。我希望时间间隔根据数据的某些属性而变化

假设我的数据是:

阶级地位 { ... 公共交通速度; }

如果速度小于100,我希望每5秒发出一次数据。如果速度高于100,则应每2秒一次


使用现成的示例()可以这样做吗?或者我需要自己构建一些东西吗?

让我知道这是否有效:

var query =
    source
        .Publish(ss =>
            ss
                .Select(s => s.Speed < 100 ? 5.0 : 2.0)
                .Distinct()
                .Select(x => ss.Sample(TimeSpan.FromSeconds(x))));
var查询=
来源
.Publish(ss=>
党卫军
.选择(s=>s.速度<100?5.0:2.0)
.Distinct()
.选择(x=>ss.Sample(TimeSpan.FromSeconds(x));

这里是一个低级实现,使用
System.Reactive.Concurrency.Scheduler.SchedulePeriodic
扩展方法作为计时器

public static IObservable<TSource> Sample<TSource>(this IObservable<TSource> source,
    Func<TSource, TimeSpan> intervalSelector, IScheduler scheduler = null)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (intervalSelector == null)
        throw new ArgumentNullException(nameof(intervalSelector));
    scheduler = scheduler ?? Scheduler.Default;

    return Observable.Create<TSource>(observer =>
    {
        TimeSpan currentInterval = Timeout.InfiniteTimeSpan;
        IDisposable timer = null;
        TSource latestItem = default;
        bool latestEmitted = true;
        object locker = new object();

        Action periodicAction = () =>
        {
            TSource itemToEmit;
            lock (locker)
            {
                if (latestEmitted) return;
                itemToEmit = latestItem;
                latestItem = default;
                latestEmitted = true;
            }
            observer.OnNext(itemToEmit);
        };

        return source.Subscribe(onNext: item =>
        {
            lock (locker)
            {
                latestItem = item;
                latestEmitted = false;
            }
            var newInterval = intervalSelector(item);
            if (newInterval != currentInterval)
            {
                timer?.Dispose();
                timer = scheduler.SchedulePeriodic(newInterval, periodicAction);
                currentInterval = newInterval;
            }
        }, onError: ex =>
        {
            timer?.Dispose();
            observer.OnError(ex);
        }, onCompleted: () =>
        {
            timer?.Dispose();
            observer.OnCompleted();
        });
    });
}
公共静态IObservable示例(此IObservable源,
Func intervalSelector,isScheduler scheduler=null)
{
如果(source==null)抛出新的ArgumentNullException(nameof(source));
if(intervalSelector==null)
抛出新ArgumentNullException(nameof(intervalSelector));
调度器=调度器??调度器。默认值;
返回可观察的。创建(观察者=>
{
TimeSpan currentInterval=Timeout.InfiniteTimeSpan;
IDisposable timer=null;
TSource latestItem=默认值;
bool latestEmitted=真;
对象锁定器=新对象();
动作周期动作=()=>
{
TSource itemToEmit;
锁(储物柜)
{
如果(延迟提交)返回;
itemToEmit=最晚的事件;
latestItem=默认值;
latestEmitted=真;
}
OnNext观察员(itemToEmit);
};
返回源。订阅(onNext:item=>
{
锁(储物柜)
{
latestItem=项目;
延迟提交=错误;
}
var newInterval=间隔选择符(项目);
如果(新间隔!=当前间隔)
{
计时器?.Dispose();
timer=scheduler.SchedulePeriodic(newInterval,periodiAction);
currentInterval=newInterval;
}
},onError:ex=>
{
计时器?.Dispose();
观察员:OnError(ex);
},未完成:()=>
{
计时器?.Dispose();
observer.OnCompleted();
});
});
}
用法示例:

observable.Sample(x => TimeSpan.FromSeconds(x.Speed < 100 ? 5.0 : 2.0));
observable.Sample(x=>TimeSpan.FromSeconds(x.Speed<100?5.0:2.0));
每当
intervalSelector
回调返回不同的间隔时,计时器就会重新启动。在极端情况下,间隔随每个新项而改变,那么此自定义运算符的行为将更像内置运算符,而不是内置运算符

示例
不同,
油门
的周期是一个滑动窗口。每次
油门
接收到一个值时,窗口都会重置。()


是的,这是可能的。@CarstenGehling,我的荣幸!