我有一个“图像”类,它有三个属性:Url,Id,Content。 我有10个这样的图像列表。 这是一个Silverlight应用程序。
我想创建一个方法:
IObservable<Image> DownloadImages(List<Image> imagesToDownload)
{
//start downloading all images in imagesToDownload
//OnImageDownloaded:
image.Content = webResponse.Content
yield image
}
此方法开始并行下载所有10个图像。 然后,当每次下载完成时,它会将Image.Content设置为该下载的WebResponse.Content。
结果应该是包含每个下载图像的IObservable流。
我是RX的初学者,我认为我想要的东西可以通过ForkJoin实现,但这是在我不想使用的反应性扩展dll的实验版本中。
另外,我真的不喜欢在回调上下载计数,以检测所有图像是否已下载,然后调用onCompleted()。
对我来说似乎没有Rx精神。
此外,我发布了到目前为止我编写的解决方案,但我不喜欢我的解决方案,因为它长/丑并且使用了计数器。
return Observable.Create((IObserver<Attachment> observer) =>
{
int downloadCount = attachmentsToBeDownloaded.Count;
foreach (var attachment in attachmentsToBeDownloaded)
{
Action<Attachment> action = attachmentDDD =>
this.BeginDownloadAttachment2(attachment).Subscribe(imageDownloadWebResponse =>
{
try
{
using (Stream stream = imageDownloadWebResponse.GetResponseStream())
{
attachment.FileContent = stream.ReadToEnd();
}
observer.OnNext(attachmentDDD);
lock (downloadCountLocker)
{
downloadCount--;
if (downloadCount == 0)
{
observer.OnCompleted();
}
}
} catch (Exception ex)
{
observer.OnError(ex);
}
});
action.Invoke(attachment);
}
return () => { }; //do nothing when subscriber disposes subscription
});
}
好的,我确实根据Jim的回答管理它以使其最终工作。
var obs = from image in attachmentsToBeDownloaded.ToObservable()
from webResponse in this.BeginDownloadAttachment2(image).ObserveOn(Scheduler.ThreadPool)
from responseStream in Observable.Using(webResponse.GetResponseStream, Observable.Return)
let newImage = setAttachmentValue(image, responseStream.ReadToEnd())
select newImage;
其中setAttachmentValue只需要`image.Content = bytes;返回图像;
BeginDownloadAttachment2代码:
private IObservable<WebResponse> BeginDownloadAttachment2(Attachment attachment)
{
Uri requestUri = new Uri(this.DownloadLinkBaseUrl + attachment.Id.ToString();
WebRequest imageDownloadWebRequest = HttpWebRequest.Create(requestUri);
IObservable<WebResponse> imageDownloadObservable = Observable.FromAsyncPattern<WebResponse>(imageDownloadWebRequest.BeginGetResponse, imageDownloadWebRequest.EndGetResponse)();
return imageDownloadObservable;
}
答案 0 :(得分:3)
我们如何简化这一点。拍摄图像列表并将其转换为可观察的图像。接下来,考虑使用Observable.FromAsyncPattern来管理服务请求。最后使用SelectMany来协调请求和响应。我在这里对你如何获取文件流做了一些假设。基本上,如果您可以将BeginInvoke / EndInvoke委托传递到FromAsyncPattern以获取服务请求,那么您很好。
var svcObs = Observable.FromAsyncPattern<Stream>(this.BeginDownloadAttachment2, This.EndDownloadAttchment2);
var obs = from image in imagesToDownload.ToObservable()
from responseStream in svcObs(image)
.ObserveOnDispatcher()
.Do(response => image.FileContent = response.ReadToEnd())
select image;
return obs;