Observable,每个订阅生成一个项目 - 每个处理程序一个事件

时间:2014-06-26 10:54:06

标签: c# .net linq system.reactive

让我们说我希望公开一个可立即通知的观察者,如果现在有互联网连接,或者如果设备没有连接到互联网,则通知会在它成为时被推出可用的:

IObservable<DateTime> InternetBecameAvailableSignalledOncePerSubscriber { get; }

此外,每个订阅应该只有一个通知,而不要求订阅者.Take(1)或类似的东西。

即。依赖于Internet资源的客户端将使用此observable立即执行某些操作或在Internet可用时立即执行某项操作,但不会多次执行此操作 - 如果Internet不可用并且可用,则不再向该订户发送信号第二次..

如何使用Reactive Extensions(Rx)实现这一点?

  • 请忽略互联网可以提供的有缺陷的概念,将其视为google.com可以访问或者您喜欢的任何风格的实现

1 个答案:

答案 0 :(得分:1)

这应该可以通过Rx轻松解决。问题是你如何知道互联网是否可用?它是基于其他订阅者订阅的,是基于另一种方法(如Connect()方法)还是某种被推送给你的事件(如WCF频道状态改变事件)?

根据这个答案,您似乎只需要封装Take(1)和Replay(1)。

public class IServiceClient
{
    IObservable<DateTime> LastConnnected { get; }
}

public class ServiceClient : IServiceClient, IDisposable
{
    private readonly IDisposable _connection;
    private readonly IObservable<DateTime> _lastConnnected;

    public ServiceClient()
    {
        //Question 1) where does the 'Connected' sequence come from i.e. what is it that tells you that you have internet connectivity?
        //Question 2) When should the subscription be made to 'Connected'? Here I cheat and do it in the ctor, not great.
        var connected = Connected.Replay(1)
                                .Where(isConnected=>isConnected)
                                .Take(1)
                                .Select(_=>DateTime.UtcNow);

        _lastConnnected = connected;
        _connection = connected.Connect();
    }

    public IObservable<DateTime> LastConnnected{ get {return _lastConnnected; } }

    public void Dispose()
    {
        _connection.Dispose();
    }
}

这确实会让您回答其他一些问题,例如:如果您有互联网连接以及资源管理计划是什么,会告诉您什么?

更新了代码

public interface IServiceClient
{
    IObservable<DateTime> LastConnnected { get; }
}

public class ServiceClient : IServiceClient, IDisposable
{
    private readonly IDisposable _connection;
    private readonly IObservable<bool> _lastConnnected;

    public ServiceClient(IObservable<ConnectionState> connectedStates)
    {
        var cachedStates = connectedStates.Select(state=>state.IsConnected).Replay(1);
        _lastConnnected = cachedStates;
        _connection = cachedStates.Connect();
    }

    public IObservable<DateTime> LastConnnected
    { 
        get 
        {
            return _lastConnnected.StartWith(IsConnected())
                                  .Where(isConnected=>isConnected)
                                  .Take(1)
                                  .Select(_=>DateTime.UtcNow); 
        } 
    }

    //....

    public void Dispose()
    {
        _connection.Dispose();
    }
}