Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.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# 具有反应扩展的划分序列_C#_.net_System.reactive - Fatal编程技术网

C# 具有反应扩展的划分序列

C# 具有反应扩展的划分序列,c#,.net,system.reactive,C#,.net,System.reactive,我有一个关于RX的小问题。我有一个来自键盘的符号流,我需要将它们分成若干组。当出现“;”时,应启动新组符号来自于流。简单地说,我需要一个类似于缓冲区的操作符,但它在某个条件为真时触发,而不是在一段时间延迟或事件计数后触发。有没有办法与RX中已有的运营商一起构建它,或者我应该自己注册吗?这里有一个来源 var source = new[] { 'a', 'b', ';', 'c', 'd', 'e', ';' }.ToObservable(); 以下是您的要求: var groups = sou

我有一个关于RX的小问题。我有一个来自键盘的符号流,我需要将它们分成若干组。当出现“;”时,应启动新组符号来自于流。简单地说,我需要一个类似于缓冲区的操作符,但它在某个条件为真时触发,而不是在一段时间延迟或事件计数后触发。有没有办法与RX中已有的运营商一起构建它,或者我应该自己注册吗?

这里有一个来源

var source = new[] { 'a', 'b', ';', 'c', 'd', 'e', ';' }.ToObservable();
以下是您的要求:

var groups = source
    // Group the elements by some constant (0)
    // and end the group when we see a semicolon
    .GroupByUntil(x => 0, group => group.Where(x => x == ';'))
以下是一种使用方法:

groups
    // Log that we're on the next group now.
    .Do(x => Console.WriteLine("Group: "))
    // Merge / Concat all the groups together
    // {{a..b..;}..{c..d..e..;}} => {a..b..;..c..d..e..;}
    .Merge()
    // Ignore the semicolons? This is optional, I suppose.
    .Where(x => x != ';')
    // Log the characters!
    .Do(x => Console.WriteLine("  {0}", x))
    // Make it so, Number One!
    .Subscribe();
输出:

Group:
  a
  b
Group:
  c
  d
  e

我们可以使用边界可观测的缓冲区覆盖,其中边界可观测是我们的初始流,仅过滤为分号条目

//this is our incoming stream
IObservable<char> keyboardStream;

//if the observable is cold we need to do this 
//in case of it being hot (as I would expect a keyboard stream to be) we do not need to do it
var persistedStream = keyboardStream.Publish().RefCount();

var bufferedBySemicolon = persistedStream.Buffer(persistedStream .Where(c=>c==';'));
//这是我们的传入流
IObservable键盘流;
//如果可见光是冷的,我们需要这样做
//如果它是热的(我希望键盘流是热的),我们不需要这样做
var persistedStream=keyboardStream.Publish().RefCount();
var bufferedBySemicolon=persistedStream.Buffer(persistedStream.Where(c=>c==';'));

这是尼古拉答案的非参考版本。这提供了订阅和处置的更明确的同步,并且应该删除当在与用户订阅的线程不同的线程上观察到源时发生的争用条件(这通常是处理UI时的情况)


这似乎简单而有趣,我倾向于不同意RefCount的大多数用法,除非不需要同步。当涉及同步时,最好是显式连接,尤其是在处理热流时。特别是,如果在订阅了
bufferedBySemicolon
的线程之外的线程上观察/生成
keyboardStream
,则此处使用RefCount是不确定的,感谢@Christopher Harris对比赛条件问题的警告(我真的不明白)。然而,这个答案非常简短,尤其是与
GroupByUntil
答案相比,这个答案似乎使用了一个过多的操作符。如果观察者很热,而我们没有
.Publish().RefCount(),是否仍然存在竞争条件,或者这个答案是否正确?GroupBy是否会创建一个新序列,该序列将在应用程序的生命周期内保持活动状态,或者我是否遗漏了什么?@L.E.O,否。GroupBy将在外部订阅的生命周期内保持对每个新GroupedObservable的引用。GroupByUntil将对每个组执行相同的操作,或者直到GroupedObservable被“until”选择器终止。对于这个实现,将只保留一个GroupedObservable,因为我们通过一个常量进行分组。实际上,这与Nikolai的答案完全相同,只是只使用了一个操作符和一个订阅。这有点道理,尽管就个人而言,不知何故,我觉得缓冲操作符是一个更符合逻辑的操作符。实际上,缓冲操作符应该有一个“直到”重载,将每个缓冲作为一个参数传递。这里的“按常量分组”逻辑确实很有味道,但在我看来,它提供了最好的结果。
var groups = Observable.Create(o => {

    var publishedSource = source.Publish();

    return new CompositeDisposable(
        publishedSource.Buffer(publishedSource.Where(c => c == ';')).Subscribe(o),
        publishedSource.Connect()
        );

});