使用任务索引超出范围异常

时间:2013-07-03 13:54:09

标签: c# task-parallel-library task

我正在使用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;
}

1 个答案:

答案 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方法中的延续。

注意,在这种情况下使用锁定对您没有帮助,因为您无法判断何时会施加锁定。它可能不会影响执行顺序,您的问题仍将存在。

我希望这会有所帮助。