2010-12-08 54 views
1

我正在使用反应式扩展来调用异步方法,并且我想要缓存结果并将其返回给该方法的后续调用。创建IObservable并立即返回缓存的异步操作的结果

如何创建一个Observable实例,将其返回并提供订阅需要的数据(cacheResult)?

public IObservable<Bar> GetBars(int pageIndex, int pageSize) 
{ 
    var @params = new object[] { pageIndex, pageSize }; 
    var cachedResult = _cache.Get(@params); 
    if (cachedResult != null) 
    { 
// How do I create a Observable instance and return the 'cacheResult'... 
return ... 
    } 

    var observable = new BaseObservable<Bar>(); 
    _components.WithSsoToken(_configuration.SsoToken) 
     .Get(@params) 
     .Select(Map) 
     .Subscribe(c => 
        { 
          _cache.Add(@params, c); 
          observable.Publish(c); 
          observable.Completed(); 
        }, exception => 
        { 
         observable.Failed(exception); 
         observable.Completed(); 
        }); 

     return observable; 
} 

回答

3

我相信你正在寻找Observable.Return

return Observable.Return((Bar)cachedResult); 

在一个不相关的注意事项:

  • 没有必要返回一个BaseObservable<T>。您应该返回一个Subject<T>,因为它可以执行您的实现,但是线程安全(您也应该在返回值上调用.AsObservable()以使其无法返回)。
  • 您使用Do的值添加到缓存:

var observable = new Subject<Bar>(); 
_components.WithSsoToken(_configuration.SsoToken) 
    .Get(@params) 
    .Select(Map) 
    .Subscribe(c => 
    { 
     _cache.Add(@params, c); 
     observable.OnNext(c); 
     observable.OnCompleted(); 
    }, exception => 
    { 
     observable.OnError(exception); 
    }); 

return observable.AsObservable(); 
+0

感谢您的回答和所有信息 – AwkwardCoder 2010-12-08 17:36:41

2

方便的是,我写了一个类,做这种模式适合你,检查出来:

https://github.com/xpaulbettsx/ReactiveXaml/blob/master/ReactiveXaml/ObservableAsyncMRUCache.cs

var cache = new ObservableAsyncMRUCache<int, int>(
    x => Observable.Return(x*10).Delay(1000) /* Return an IObservable here */, 
    100 /*items to cache*/, 
    5 /* max in-flight, important for web calls */ 
    ); 

IObservable<int> futureResult = cache.AsyncGet(10); 

futureResult.Subscribe(Console.WriteLine); 
>>> 100 

,它正确地处理一些棘手的事情:

  • 它缓存最近n项和扔掉未使用
  • 它确保不超过n项是在同一运行项目时间 - 如果您不这样做,如果缓存为空,您可以轻松产生数千个网络电话
  • 如果您连续询问同一项目两次,第一个请求将启动一个请求,第二个请求调用将等待第一个调用,而不是产生相同的请求,因此您不会最终重复查询数据。