强制同步响应式扩展调用

本文关键字:扩展 调用 响应 同步 | 更新日期: 2023-09-27 18:14:51

我正在编写一些代码,看起来像这样:

public class ManagerViewModel : ManagerViewModelBase
{
  public ManagerViewModel(ISettingsProvider settingsProvider):
    base(settingsProvider.Settings)
}

public class ManagerViewModelBase
{
  private IEnumerable<string> _mySettings = Enumerable.Empty<string>();
  public ManagerViewModelBase(IEnumerable<string> settings)
  {
    _mySettings = settings;
  }
}

ISettingsProvider是通过Unity提供的,看起来像:

public class SettingsProvider : ISettingsProvider 
{
  private readonly Service _service;
  IEnumerable<string> _settings = Enumerable.Empty<string>();
  public IEnumerable<string> Settings {get {return _settings}};
  public SettingsProvider (
    IService _service,
    ISettingsProvider settingsProvider)
  {
    _service = service;
    LoadSettings();
  }
  private void LoadSettings()
  {
    //_service just supplies the data              
    _service.GetSettings.Subscribe(LoadSettingsCompleted);
  }
  private void LoadSettingsCompleted(IEnumerable<string> settings)
  {
    _settings = settings;
  }
}

问题是,当SettingsProvider实例化时,可能需要一点时间才能从服务调用中获得结果,因此,在调用完成并填充_settings之前,进行了基本(SettingsProvider . settings)调用,基本上传递了一个空枚举。

是否有一种方法可以使SettingsProvider。属性调用等待,直到数据从服务返回。GetSettings调用是可用的,并且在一定的时间后超时?我想我正在寻找最简单的方法来阻止这个属性调用。

谢谢。

强制同步响应式扩展调用

我意识到你的问题是如何等待/阻塞,但我必须告诉你,你可能不应该。很可能你的ViewModel是在UI线程中创建的,阻塞是你想要的最后一件事。

如果你的ViewModel依赖于一些异步的东西,那么它的创建是异步的,你应该用等待隐藏它。不能使用Async in构造函数,但是你可以将你的VM构造函数设为私有,并公开一个Async静态工厂方法,比如:

private ManagerViewModel(IEnumerable<string> settings) : base(settings) {}
public async Task<ManagerViewModel> CreateAsync(ISettingsProvider settingsProvider) {
    var settings = await settingsProvider.GetSettingsAsync();
    return new ManagerViewModel(settings);
}
// ....
public async Task<IEnumerable<Settings>> GetSettingsAsync() {
    return await _service.GetSettings().Timeout(...).FirstAsync();
}

我的建议是始终使用async并且永远不要阻塞。

这些都不是很反应性,但是您可以阻止使用Observable.FirstAsync()Observable.Wait()扩展方法。所以你的LoadSettings()方法看起来像这样:

private void LoadSettings()
{
    _settings = _service.GetSettings
                        .Timeout(_expireTime, Observable.Return(Enumerable.Empty<string>()))
                        .FirstAsync()
                        .Wait();
    _service.GetSettings.Subscribe(LoadSettingsCompleted);
}