Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.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# 对于无功扩展(RX),是否可以添加一个;暂停“;指挥部?_C#_.net_System.reactive_Reactive Programming_Rx.net - Fatal编程技术网

C# 对于无功扩展(RX),是否可以添加一个;暂停“;指挥部?

C# 对于无功扩展(RX),是否可以添加一个;暂停“;指挥部?,c#,.net,system.reactive,reactive-programming,rx.net,C#,.net,System.reactive,Reactive Programming,Rx.net,我有一个类,它接收一个事件流,然后推出另一个事件流 所有事件都使用无功扩展(RX)。使用.OnNext将传入的事件流从外部源推送到IObserver,并使用IObservable和订阅将传出的事件流推出。我在幕后使用Subject来管理这个 我想知道RX中有什么技术可以暂时暂停输出。这意味着传入事件将在内部队列中累积,当它们未暂停时,事件将再次流出 您可以使用可观察的模拟暂停/取消暂停 一旦pauseObservable发出“暂停”值,缓冲事件,直到pauseObservable发出“未暂停”值

我有一个类,它接收一个事件流,然后推出另一个事件流

所有事件都使用无功扩展(RX)。使用
.OnNext
将传入的事件流从外部源推送到
IObserver
,并使用
IObservable
订阅将传出的事件流推出。我在幕后使用
Subject
来管理这个


我想知道RX中有什么技术可以暂时暂停输出。这意味着传入事件将在内部队列中累积,当它们未暂停时,事件将再次流出

您可以使用可观察的
模拟暂停/取消暂停

一旦pauseObservable发出“暂停”值,缓冲事件,直到pauseObservable发出“未暂停”值

下面是一个使用and的示例(来自我刚才的问题)

//输入事件,热可观察
var source=可观测的时间间隔(时间跨度从秒(1))开始)
.Select(i=>i.ToString())
.Publish().RefCount();
//模拟键盘上的暂停,实际上与此答案无关
var pauseObservable=Observable.FromEventPattern(
k=>KeyPressed+=k,k=>KeyPressed-=k)
.Select(i=>i.EventArgs.PressedKey)
.Select(i=>i==ConsoleKey.Spacebar)//空格表示暂停,其他空格表示取消暂停
.DistinctUntilChanged();
//让事件在未暂停时通过
var notPausedEvents=source.Zip(pauseObservable.MostRecent(false),(值,暂停)=>new{value,暂停})
.Where(i=>!i.paused)//未暂停
.选择(i=>i.value)
.Subscribe(Console.WriteLine);
//暂停时,缓冲直到未暂停
var pausedEvents=pauseObservable.Where(i=>i)
.Subscribe(=>
source.BufferUntil(pauseObservable.Where(i=>!i))
.Select(i=>String.Join(Environment.NewLine,i))
.Subscribe(Console.WriteLine));

改进空间:也许可以将源代码的两个订阅(pausedEvents和notPausedEvents)合并为一个。

这里有一个相当简单的Rx方法来实现您想要的功能。我创建了一个名为
Pausable
的扩展方法,它获取一个源可观测值和一个
boolean
的第二个可观测值,用于暂停或恢复可观测值

public static IObservable<T> Pausable<T>(
    this IObservable<T> source,
    IObservable<bool> pauser)
{
    return Observable.Create<T>(o =>
    {
        var paused = new SerialDisposable();
        var subscription = Observable.Publish(source, ps =>
        {
            var values = new ReplaySubject<T>();
            Func<bool, IObservable<T>> switcher = b =>
            {
                if (b)
                {
                    values.Dispose();
                    values = new ReplaySubject<T>();
                    paused.Disposable = ps.Subscribe(values);
                    return Observable.Empty<T>();
                }
                else
                {
                    return values.Concat(ps);
                }
            };

            return pauser.StartWith(false).DistinctUntilChanged()
                .Select(p => switcher(p))
                .Switch();
        }).Subscribe(o);
        return new CompositeDisposable(subscription, paused);
    });
}
public static IObservable Pausable(
这是一个可观测的来源,
IObservable暂停器)
{
返回可观察的。创建(o=>
{
var paused=new SerialDisposable();
var订阅=可观察的。发布(来源,ps=>
{
var值=新的ReplaySubject();
Func切换器=b=>
{
如果(b)
{
value.Dispose();
值=新的ReplaySubject();
暂停。一次性=ps.Subscribe(值);
return-Observable.Empty();
}
其他的
{
返回值:Concat(ps);
}
};
返回pauser.StartWith(false).DistinctUntilChanged()
.选择(p=>switcher(p))
.开关();
}).认购(o);
返回新的CompositeDisposable(订阅,暂停);
});
}
它可以这样使用:

var xs = Observable.Generate(
    0,
    x => x < 100,
    x => x + 1,
    x => x,
    x => TimeSpan.FromSeconds(0.1));

var bs = new Subject<bool>();

var pxs = xs.Pausable(bs);

pxs.Subscribe(x => { /* Do stuff */ });

Thread.Sleep(500);
bs.OnNext(true);
Thread.Sleep(5000);
bs.OnNext(false);
Thread.Sleep(500);
bs.OnNext(true);
Thread.Sleep(5000);
bs.OnNext(false);
var xs=Observable.Generate(
0,
x=>x<100,
x=>x+1,
x=>x,
x=>TimeSpan.FromSeconds(0.1));
var bs=新主题();
var pxs=xs.可暂停(bs);
订阅(x=>{/*Do stuff*/});
睡眠(500);
bs.OnNext(真实);
睡眠(5000);
bs.OnNext(假);
睡眠(500);
bs.OnNext(真实);
睡眠(5000);
bs.OnNext(假);

现在,我唯一不能完全理解你所说的“传入事件流是一个
IObserver
”是什么意思。流是可观察的。观察者不是溪流。听起来你好像没在这里做什么。您能补充您的问题并进一步解释吗?

以下是我使用缓冲区和窗口运算符的解决方案:

public static IObservable<T> Pausable<T>(this IObservable<T> source, IObservable<bool> pauser)
{
    var queue = source.Buffer(pauser.Where(toPause => !toPause),
                              _ => pauser.Where(toPause => toPause))
                      .SelectMany(l => l.ToObservable());

    return source.Window(pauser.Where(toPause => toPause).StartWith(true), 
                         _ => pauser.Where(toPause => !toPause))
                 .Switch()
                 .Merge(queue);
}
公共静态IObservable Pausable(此IObservable源,IObservable pauser)
{
var queue=source.Buffer(pauser.Where(toPause=>!toPause)),
_=>pauser.Where(toPause=>toPause))
.SelectMany(l=>l.ToObservable());
返回source.Window(pauser.Where(toPause=>toPause).StartWith(true),
_=>pauser.Where(toPause=>!toPause))
.Switch()
.合并(队列);
}
窗口在订阅时打开,并且每次从pauser stream接收到“true”时都会打开。当pauser提供“false”值时,它关闭

缓冲区执行它应该执行的操作,缓冲来自pauser的介于“false”和“true”之间的值。一旦缓冲区接收到“true”,它将立即输出一次流式传输的IList值


DotNetFiddle link:

认为如果输出暂停,可能会将事件重定向到内部队列,并且当outout暂停时,它可能会刷新队列。您还没有实现自己的
IObserver
,是吗?否,我所做的只是将内部
主题
强制转换为
IObserver
,这样方法
.OnNext
就可以公开了。谢谢你的回答。我已经更新了我的问题,以使数据流更清晰。照目前的情况,这显然没有让第一个值通过,因为它通过了假分支,并希望将
值浓缩到
(这实际上是
可观察的。我想永远不会
)。我第一次将
值初始化为null,并检入两个分支,从而使它成形。不确定是否还有更优雅的。进一步警告未来的自我<代码>ReplaySubject<
public static IObservable<T> Pausable<T>(this IObservable<T> source, IObservable<bool> pauser)
{
    var queue = source.Buffer(pauser.Where(toPause => !toPause),
                              _ => pauser.Where(toPause => toPause))
                      .SelectMany(l => l.ToObservable());

    return source.Window(pauser.Where(toPause => toPause).StartWith(true), 
                         _ => pauser.Where(toPause => !toPause))
                 .Switch()
                 .Merge(queue);
}