我正在使用Task.FromAsync和Task.ContinueWith方法来完成我的工作。我在我的程序中使用List,当我运行它时,它给了我一个Index Out of Range Exception。但是,当我通过调试器时,它会运行并完成就好了。是否存在我缺少的内容,或者在使用循环和列表时,任务的操作方式有何不同?
public int TimerCounter = 0;
public IList<WebsiteResult>webResult = new List<WebsiteResult>();
public void sendRequest(){
foreach(Website web in TempVar._allWebsites)
{
webResult.Add(new WebSiteResult {});
try
{
pageCheck(web);
webResult.ElementAt(TimerCounter).RequestSentTime = DateTime.Now.ToString();
if(webResult.ElementAt(TimerCounter).SystemStatus == null)
webResult.ElementAt(TimerCounter).SystemStatus = "";
TimeCounter++;
}
}
public void pageCheck(){
IAsyncResult asyncResult;
Uri uri = new Uri(TempURL); //TempUrl is assigned a string beforehand
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(uri);
try{
Task<WebResponse> task = Task.Factory.FromAsync(
myReq.BeginGetResponse,
asyncResult => myReq.EndGetResponse(asyncResult),
(Object)null);
task.ContinueWith(t =>
{
var responseCode = (HttpWebResponse)t.Result;
ReadStreamFromResponse(t.Result);
if(responseCode.StatusCode == HttpStatusCode.OK){
webResult.ElementAt(TimerCounter).ResponseStatusCode = "Up"; //Error occurs here
reponseCode.Close();
}
}
);
}
//catch exceptions
}
private String ReadStreamFromResponse(WebResponse response) {
StreamReader responseStream = new StreamReader(response.GetResponseStream());
string str = responseStream.ReadToEnd();
return str;
}
答案 0 :(得分:2)
这是因为您对pageCheck()
的调用设置了在Task
完成/完成时运行的延续。但是,在设置并关闭pageCheck()
之后,对sendRequest()
方法的调用几乎会立即返回给调用者(Task
)。您的Task
将花费时间在后台线程池线程上执行,但会快速将控制权返回给sendRequest()
,然后尝试访问您的IList
,其中没有元素,因为这些元素已填入延续。此可能 如果您逐步使用调试器,这会影响Task
被触发的方式并影响操作顺序 - 因此可以影响这些操作的结果。
我的建议是把你的
Task
进入task.ContinueWith(t =>
{
var responseCode = (HttpWebResponse)t.Result;
ReadStreamFromResponse(t.Result);
if(responseCode.StatusCode == HttpStatusCode.OK)
{
webResult.ElementAt(TimerCounter).ResponseStatusCode = "Up"; //Error occurs here
reponseCode.Close();
}
webResult.ElementAt(TimerCounter).RequestSentTime = DateTime.Now.ToString();
if(webResult.ElementAt(TimerCounter).SystemStatus == null)
webResult.ElementAt(TimerCounter).SystemStatus = "";
TimeCounter++;
});
内的延续。另一个选项是创建另一个方法,将此流程包装在“更高级别的任务”中,您可以设置pageCheck()
和Task
方法中的延续。
注意,在这种情况下使用锁定对您没有帮助,因为您无法判断何时会施加锁定。它可能不会影响执行顺序,您的问题仍将存在。
我希望这会有所帮助。