C# 如何在rx.net中实现我自己的运营商

C# 如何在rx.net中实现我自己的运营商,c#,system.reactive,rx.net,C#,System.reactive,Rx.net,我需要RX中滞后滤波器的功能。仅当先前发出的值与当前输入值相差一定量时,它才应从源流发出值。作为通用扩展方法,它可以具有以下签名: 公共静态IObservable滞后过滤器(此IObservable源,Func过滤器) 我不知道如何在现有的运营商中实现这一点。我在寻找RxJava之类的东西,任何其他方法都可以创建我自己的操作符。我已经看到了这一点,但我没有在网上找到任何例子 以下方法(实际上都是相同的)对我来说似乎是可行的,但是有没有更有效的方法来做到这一点,比如不包装主题或实际实现操作符 a

我需要RX中滞后滤波器的功能。仅当先前发出的值与当前输入值相差一定量时,它才应从源流发出值。作为通用扩展方法,它可以具有以下签名:

公共静态IObservable滞后过滤器(此IObservable源,Func过滤器)
我不知道如何在现有的运营商中实现这一点。我在寻找RxJava之类的东西,任何其他方法都可以创建我自己的操作符。我已经看到了这一点,但我没有在网上找到任何例子

以下方法(实际上都是相同的)对我来说似乎是可行的,但是有没有更有效的方法来做到这一点,比如不包装
主题
或实际实现操作符

async Task Main()
{
var cts=新的CancellationTokenSource(TimeSpan.FromSeconds(5));
var rnd=新随机数();
var s=可观察的时间间隔(时间跨度从毫秒(10))
.Scan(0d,(a,))=>a+rnd.NextDouble()-0.5)
.Publish()
.自动连接()
;
s、 订阅(Console.WriteLine,cts.Token);
s、 癔病过滤器((p,c)=>Math.Abs(p-c)>1d.Subscribe(x=>Console.WriteLine($“1>{x}”),cts.Token;
s、 癔症过滤器2((p,c)=>Math.Abs(p-c)>1d.Subscribe(x=>Console.WriteLine($“2>{x}”),cts.Token;
wait Task.Delay(Timeout.InfiniteTimeSpan,cts.Token).ContinueWith(=>u,TaskContinuationOptions.onlyOnCancelled);
}
公共静态类反应运算符
{
公共静态IObservable滞后过滤器(此IObservable源,Func过滤器)
{
返回新的InternalResisteSFilter(源,筛选器)。A可观察;
}
公共静态IObservable滞后过滤器2(此IObservable源,Func过滤器)
{
var subject=新的subject();
T=默认值;
bool=false;
来源:订阅(
值=>
{
如果(!已发射| |过滤器(上次发射,值))
{
subject.OnNext(值);
LastEmissed=值;
发射=真;
}
} 
,ex=>subject.OnError(ex)
,()=>subject.OnCompleted()
);
返回主题;
}
私有类InternalResistesFilter:IObserver
{
Func滤波器;
T最后发射;
布尔发射;
私有只读主题=新主题();
公共IObservable asobbservable=>subject;
公共内部滞后过滤器(IObservable源,Func过滤器)
{
this.filter=过滤器;
来源:订阅(本);
}
公共IDisposable订阅(IObserver观察员)
{
返回主题。订阅(观察员);
}
公共void OnNext(T值)
{
如果(!已发射| |过滤器(上次发射,值))
{
subject.OnNext(值);
LastEmissed=值;
发射=真;
}
}
公共无效OnError(异常错误)
{
主语。一个错误(错误);
}
未完成的公共无效()
{
subject.OnCompleted();
}
}
}

旁注:将有数千个这样的过滤器应用于尽可能多的流。我需要延迟的吞吐量,因此我正在寻找CPU和内存开销最小的解决方案,即使其他人看起来更喜欢

我在书中看到的大多数示例都使用了创建新操作符的方法
Observable.Create

createfactory方法是实现定制可观察序列的首选方法。受试者的使用应主要停留在样本和测试领域。()

公共静态IObservable滞后过滤器(此IObservable源,
Func谓词)
{
返回可观察的。创建(观察者=>
{
T=默认值;
bool=false;
返回source.Subscribe(值=>
{
if(!emissed | |谓词(lastEmissed,value))
{
observer.OnNext(值);
LastEmissed=值;
发射=真;
}
},observer.OnError,observer.OnCompleted);
});
}

这个答案与@Theodor的答案相同,但它避免使用我通常会避免的
Observable.Create

public static IObservable<T> HysteresisFilter2<T>(this IObservable<T> source,
    Func<T, T, bool> predicate)
{
    return source
        .Scan((emitted: default(T), isFirstItem: true, emit: false), (state, newItem) => state.isFirstItem || predicate(state.emitted, newItem)
            ? (newItem, false, true)
            : (state.emitted, false, false)
        )
        .Where(t => t.emit)
        .Select(t => t.emitted);
}
public static IObservable resistesfilter2(此IObservable源,
Func谓词)
{
返回源
.Scan((发出:默认值(T),isFirstItem:true,发出:false),(状态,newItem)=>state.isFirstItem | |谓词(state.emissed,newItem)
?(新项、假项、真项)
:(state.emission,false,false)
)
.其中(t=>t.emit)
。选择(t=>t);
}

.Scan
是在可观察范围内跟踪项目状态时要使用的工具

是的,这听起来很合理。这也意味着在Rx.Net中没有用户定义的操作员?然而,这种方法看起来干净而且便宜。我以前没有听说过“用户定义运算符”这个术语,所以它可能不是一个公认的术语。但不要相信我的话,因为我不是一个经验丰富的RX用户。:-)可能不是一个固定的术语,但我正在寻找类似于我在第一篇链接文章中引用的内容。在RxJava中,它看起来是一个
操作符
接口,但我自己从未使用过它。在对象浏览器(Ctrl+W,J)中搜索“操作符”显示出与RX无关的内容,所以我猜这个概念还没有被.NET采用。除非它包含在一个单独的包中,但我在NuGet包管理器中也看不到任何相关内容。Operator不是Rx.net中的接口。你可以粗略地把它看作是
public static IObservable<T> HysteresisFilter2<T>(this IObservable<T> source,
    Func<T, T, bool> predicate)
{
    return source
        .Scan((emitted: default(T), isFirstItem: true, emit: false), (state, newItem) => state.isFirstItem || predicate(state.emitted, newItem)
            ? (newItem, false, true)
            : (state.emitted, false, false)
        )
        .Where(t => t.emit)
        .Select(t => t.emitted);
}