我希望在第一个客户端连接时向我的服务器发送一个启动脉冲,并在最后一个客户端断开连接时发送一个完成脉冲。
public class MyAdapter : IObservable<MyType> {
IObservable<MyType> MyObservable = BuildMyObservable()
.Initially(Start) // <- this method doesn't exist
.Finally(Stop).Publish().RefCount().Subscribe(observer);
public IDisposable Subscribe(IObserver<MyType> observer);
return MyObservable.Subscribe(observer)
}
async Task Start() { /* start UDP stream */ }
async Task Stop() { /* stop UDP stream */ }
IObservable<MyType> BuildMyObservable() { /* wire up stuff */ }
}
在上面的方法中,我是否正在寻找一个不存在的函数Initially
,或者我只是忽略它?
答案 0 :(得分:3)
您可以像处理任何其他序列一样处理任务,并将其链接到查询
Start().ToObservable()
.SelectMany(_=>MyObservable)
.Finally(Stop)
作为单独的说明,我建议您避免制作采用格式为IDisposable Subscribe(IObserver<MyType> observer)
的方法的API。这消除了消费者对Rx的影响。相反,只需公开IObservable<T>
,因为它已经有Subscribe
方法。现在,您的消费者可以链接您的序列,组合它,选择正确的并发/线程模型(使用ObserveOn
/ SubscribeOn
),并应用它们的错误处理要求。
另外作为最后一点,发布-refcount一个方法调用结果的序列有点奇怪。当您的方法仅允许消费者提供一个消费者时,发布-refcount更加奇怪。假设您将方法签名更改为推荐/标准方法,那么我还建议您删除Publish().Refcount()
代码,因为消费者极不可能缓存结果并重新使用它,v。回想一下这个方法。或者您可以保留方法(甚至更好地将其更改为属性),然后在内部缓存已发布的序列。
public class MyServiceThing
{
private readonly IObservable<MyType> _myObservable;
public MyServiceThing()
{
_myObservable = Start().ToObservable()
.SelectMany(_=>/*The thing that defines your observable sequence...*/)
.Finally(Stop)
.Publish().RefCount();
}
public IObservable<MyType> MyObservable()
{
return _myObservable;
}
//OR
//public IObservable<MyType> MyObservable() { get { return _myObservable; } }
private async Task Start() {}
private async Task Stop() {}
}
答案 1 :(得分:2)
我猜你正在寻找来自RxJava的.Net等价的doOnSubscribe。它不是开箱即用的。
您可以做的是将MyObservable
包裹在Observable.Defer
函数中,并在Defer
内调用您的服务器。您可以使用以下代码来查看我的意思:
class Program
{
static void Main(string[] args)
{
var source = Observable.Interval(TimeSpan.FromSeconds(1));
var published = Observable.Defer(() =>
{
Console.WriteLine("Start"); // Here, you post "Start" to server
return source;
})
.Finally(() => Console.WriteLine("End")) // Here, you post "End"
.Publish()
.RefCount();
Console.ReadLine();
var disposable = published.Subscribe(x => Console.WriteLine("First " + x));
Console.ReadLine();
var disposable2 = published.Subscribe(x => Console.WriteLine("Second " + x));
Console.ReadLine();
disposable.Dispose();
Console.ReadLine();
disposable2.Dispose();
Console.ReadLine();
published.Subscribe(x => Console.WriteLine("Third " + x));
Console.ReadLine();
}
}
有关延期的更多说明,请参阅this excellent blogpost。
答案 2 :(得分:0)
使用pmbanka的正确答案,我为此添加了一个Observable扩展名。
public static IObservable<T> Initially<T>(this IObservable<T> resultingObservable, Func<Task> initialAction) {
return Observable.Defer(async () =>
{
await initialAction();
return resultingObservable;
});
}
public static IObservable<T> Initially<T>(this IObservable<T> resultingObservable, Action initialAction) {
return Observable.Defer(() =>
{
Action();
return resultingObservable;
});
}
它尚未经过测试,可能不是最佳的async / task lambdas。
我想以下内容也是如此:
public static IObservable<T> Initially<T>(this IObservable<T> resultingObservable, Func<Task> initialAction) {
return Observable.Create(async (IObserver<T> observer) =>
{
await initialAction();
return resultingObservable.Subscribe(observer);
});
}