我正在使用 Task.FromAsync 和 Task.ContinueWith 方法来完成我的工作。我在我的程序中使用了一个列表,当我运行它时,它给了我一个索引超出范围异常。但是,当我通过调试器时,它会运行并完成。将任务与循环和列表一起使用时,我是否遗漏了什么或它们的运行方式不同?
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;
}
最佳答案
这是因为您对 pageCheck()
的调用设置了一个延续,它将在 Task
结束/完成时运行。但是,对 pageCheck()
方法的调用将在设置和结束您的 Task
后立即返回给调用者 (sendRequest()
) >。您的 Task
将需要时间在后台线程池线程上执行,但会很快将控制返回给 sendRequest()
,然后它会尝试访问您的 IList
将没有元素,因为这些元素是在延续中填充的。这可能工作有时取决于线程池优化器如何分派(dispatch)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
并在 sendRequest()
中继续方法代替。
请注意,在这种情况下使用锁对您没有帮助,因为您不知道何时会施加锁。它可能不会影响执行顺序,您的问题仍然存在。
希望对您有所帮助。
关于c# - 使用任务索引超出范围异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17449926/