我的 lightswitch 应用程序中有一个函数,可以从网站下载 csv 文件,我想使用 Rx 框架重写该文件,并提供同步调用它的可能性。
下面提供的是旧函数和新函数的代码片段。然而,新函数不起作用,对 ParseCSV 的调用永远不会发生。我想知道为什么,如果有更好的解决方案,请随时提供。
旧代码:
private void ObservableCollection<Data> collection;
public ObservableCollection<Data> GetData(string url, ObservableCollection<Data> targetCollection)
{
collection = targetCollection;
if (!string.IsNullOrEmpty(url))
{
WebClient wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(OpenReadCompleted_ParseCSV);
wc.OpenReadAsync(new Uri(url));
}
return collection;
}
private void OpenReadCompleted_ParseCSV(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null) return;
var webClient = sender as WebClient;
if (webClient == null) return;
try
{
using (StreamReader reader = new StreamReader(e.Result))
{
string contents = reader.ReadToEnd();
...
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Error parsing CSV!\n" + ex.Message);
}
}
新代码(带 Rx):
private void ObservableCollection<Data> collection;
public ObservableCollection<Data> GetData(string url, ObservableCollection<Data> targetCollection)
{
collection = targetCollection;
if (!string.IsNullOrEmpty(url))
{
var result = Observable.FromEventPattern<OpenReadCompletedEventHandler, OpenReadCompletedEventArgs>
(
ev => webClient.OpenReadCompleted += ev,
ev => webClient.OpenReadCompleted -= ev
)
.Select(o => o.EventArgs.Result)
.FirstOrDefault()
.ParseCSV();
// Call the Async method
webClient.OpenReadAsync(new Uri(url));
}
return collection;
}
private void ParseCSV(this Stream stream)
{
try
{
using (StreamReader reader = new StreamReader(e.Result))
{
string contents = reader.ReadToEnd();
...
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Unable to get history data!\n" + ex.Message);
}
}
最佳答案
很难知道你想要什么(我认为你试图简化在 StackOverflow 上发布的代码,并且在翻译中丢失了很多内容),但我认为对此我没有什么可以改变的。
我注意到的一件事是您正在主线程上解析结果。您可能会这样做是有原因的,但您可能会考虑以下几点:
//Note the void here. Is your intention to return a new collection or contribute
//to an existing one? I assumed the latter and changed the method to be more clear
//that this method causes side effects.
public void GetData(string url, ObservableCollection<Data> targetCollection)
{
var result = Observable
.FromEventPattern<OpenReadCompletedEventHandler, OpenReadCompletedEventArgs>
(
ev => webClient.OpenReadCompleted += ev,
ev => webClient.OpenReadCompleted -= ev
)
.Select(o => ParseCSV(o.EventArgs.Result));
result.Subscribe(targetCollection.Add);
webClient.OpenReadAsync(new Uri(url));
}
//This method now returns a Data object read from a Stream
private static Data ParseCSV(Stream stream)
{
try
{
using (StreamReader reader = new StreamReader(stream))
{
string contents = reader.ReadToEnd();
//...
return data;
}
}
catch (Exception ex)
{
//Use Exception.ToString(). You get error and stack trace information
//For this error as well as any inner exceptions. Nice!
System.Diagnostics.Debug.WriteLine("Unable to get history data!\n" + ex.ToString());
}
return null;
}
在这里,对于从 webClient 请求返回的每个值(只有一个),我们将结果投影到您的 Data
类中,而不是执行可观察流之外的转换。
我对你的方法做了一些小修改。我不太喜欢这样带有副作用的代码(传递集合来贡献似乎是错误的向量),但我会允许它。除此之外,我认为这应该效果很好。
关于.net - Observable 和 Webclient 获取 csv,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9308744/