使用直接方法创建可观察对象

Create observables using straight methods

我需要重新收集一些调用方法的数据正在连接到网络服务。

问题: 假设我需要根据远程收集的信息更新标签控件的内容文本。在重新收集所有这些数据之前,我无法展示标签。

desired: 我想首先显示带有默认文本的标签,当我收到此信息时,我想更新标签内容(请不要不要把这个描述当成烂代码,我只是简单介绍一下我的真实情况)。

我想创建这些方法的可观察序列。然而,这些方法没有相同的签名。例如:

int GetInt() {
    return service.GetInt();
}

string GetString() {
    return service.GetString();
}

string GetString2 {
    return service.GetString2();
}

这些方法不是async

  1. 是否可以创建这些方法的可观察序列?

  2. 如何创建它?

  3. 然而,实现我的目标的最佳选择是什么?

可以使用 Observable.Create 实现创建自定义可观察序列。使用您的要求的示例如下所示:

private int GetInt()
{
    Thread.Sleep(1000);

    return 1;
}

private string GetString()
{
    Thread.Sleep(1000);

    return "Hello";
}

private string GetString2()
{
    Thread.Sleep(2000);

    return "World!";
}

private IObservable<string> RetrieveContent()
{
    return Observable.Create<string>(
        observer =>
        {
            observer.OnNext("Default Text");

            int value = GetInt();

            observer.OnNext($"Got value {value}. Getting string...");

            string string1 = GetString();

            observer.OnNext($"Got string {string1}. Getting second string...");

            string string2 = GetString2();

            observer.OnNext(string2);
            observer.OnCompleted();

            return Disposable.Empty;
        }
    );
}

请注意我是如何通过在每个 GetXXX 方法中引入 Thread.Sleep 调用来模拟网络延迟的。为了确保你的 UI 在订阅这个 observable 时不会挂起,你应该按如下方式订阅:

IDisposable subscription = RetrieveContent()
  .SubscribeOn(TaskPoolScheduler.Default)
  .ObserveOn(DispatcherScheduler.Current)
  .Subscribe(text => Label = text);

此代码使用 .SubscribeOn(TaskPoolScheduler.Default) 扩展方法来使用 TaskPool 线程启动可观察序列,并且会被 Thread.Sleep 调用阻塞,但是,因为这不是 UI 线程,您的 UI 将保持响应。然后,为了确保我们在 UI 线程上更新 UI,我们使用“.ObserveOn(DispatcherScheduler.Current)”在设置(数据绑定)Label 属性.

希望这就是您要找的东西,如果不是,请发表评论,我会尽力提供进一步帮助。

我会考虑为您的服务创建包装器 class 以将值公开为单独的可观察值。

所以,从服务接口开始:

public interface IService
{
    int GetInt();
    string GetString();
    string GetString2();
}

...然后你写 ServiceWrapper:

public class ServiceWrapper : IService
{
    private IService service;
    private Subject<int> subjectGetInt = new Subject<int>();
    private Subject<string> subjectGetString = new Subject<string>();
    private Subject<string> subjectGetString2 = new Subject<string>();

    public ServiceWrapper(IService service)
    {
        this.service = service;
    }

    public int GetInt()
    {
        var value = service.GetInt();
        this.subjectGetInt.OnNext(value);
        return value;
    }

    public IObservable<int> GetInts()
    {
        return this.subjectGetInt.AsObservable();
    }

    public string GetString()
    {
        var value = service.GetString();
        this.subjectGetString.OnNext(value);
        return value;
    }

    public IObservable<string> GetStrings()
    {
        return this.subjectGetString.AsObservable();
    }

    public string GetString2()
    {
        var value = service.GetString2();
        this.subjectGetString2.OnNext(value);
        return value;
    }

    public IObservable<string> GetString2s()
    {
        return this.subjectGetString2.AsObservable();
    }
}

现在,假设您当前的服务称为 Service,您将编写此代码来进行设置:

IService service = new Service();
ServiceWrapper wrapped = new ServiceWrapper(service); // Still an `IService`

var subscription =
    Observable
        .Merge(
            wrapped.GetInts().Select(x => x.ToString()),
            wrapped.GetStrings(),
            wrapped.GetString2s())
        .Subscribe(x => label.Text = x);

IService wrappedService = wrapped;

现在将 wrappedService 而不是 service 传递给您的代码。它仍在调用底层 service 代码,因此不需要 re-write,但您仍然可以获得所需的可观察值。

这实际上是四人组 decorator pattern