2012-10-19 120 views
0

我的意思是不要暫停和恢復,而是取消/停止。 暫停和恢復,我在Form1的頂部使用這樣的:如何停止遞歸循環?

System.Threading.ManualResetEvent _busy = new System.Threading.ManualResetEvent(true); 

然後在按鈕Im做_busy.Reset();和_busy.Set();暫停和恢復。 但是,如果我想完全停止/取消recrusive循環?

這是遞歸循環代碼:

private List<string> test(string url, int levels,DoWorkEventArgs eve) 
     { 
      _busy.WaitOne(); 
      if (cancel == true) 
      { 

      } 
      this.Invoke(new MethodInvoker(delegate { label3.Text = label3.Text = (Int32.Parse(label12.Text) + Int32.Parse(label10.Text)).ToString(); })); 


      HtmlWeb hw = new HtmlWeb(); 
      List<string> webSites; 
      List<string> csFiles = new List<string>(); 

      csFiles.Add("temp string to know that something is happening in level = " + levels.ToString()); 
      csFiles.Add("current site name in this level is : " + url); 
      try 
      { 
       this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, "Level: " + levels.ToString(), Color.Green); })); 
       this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, " Loading The Url: " , Color.Red); })); 
       this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, url + "...",Color.Blue); })); 
       HtmlAgilityPack.HtmlDocument doc = TimeOut.getHtmlDocumentWebClient(url, false, "", 0, "", ""); 

       this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, " Done " + Environment.NewLine, Color.Red); })); 


        currentCrawlingSite.Add(url); 
        webSites = getLinks(doc); 
        removeDupes(webSites); 
        removeDuplicates(webSites, currentCrawlingSite); 
        removeDuplicates(webSites, sitesToCrawl); 
        if (removeExt == true) 
        { 
         for (int i = 0; i < webSites.Count; i++) 
         { 
          webSites.Remove(removeExternals(webSites)); 
         } 
        } 
        if (downLoadImages == true) 
        { 
         webContent.retrieveImages(url);      } 
        } 
        if (levels > 0) 
         sitesToCrawl.AddRange(webSites) 
        this.Invoke(new MethodInvoker(delegate { label7.Text = sitesToCrawl.Count.ToString(); })); 
        this.Invoke(new MethodInvoker(delegate { label12.Text = currentCrawlingSite.Count.ToString(); })); 


        if (levels == 0) 
        { 
         return csFiles; 
        } 
        else 
        { 


         for (int i = 0; i < webSites.Count(); i++)//&& i < 20; i++)       { 



          string t = webSites[i]; 
          if ((t.StartsWith("http://") == true) || (t.StartsWith("https://") == true)) 
          { 
           csFiles.AddRange(test(t, levels - 1, eve));         
          } 

         } 
         return csFiles; 
        } 



      } 
      catch 
      { 
       failedUrls++; 
       this.Invoke(new MethodInvoker(delegate { label10.Text = failedUrls.ToString(); })); 
       this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, " Failed " + Environment.NewLine, Color.Green); })); 
       return csFiles; 
      } 

     } 

我有一個按鈕單擊事件取消/停在那裏我有一個標誌,我設置爲true,那麼在遞歸循環上面我所做的:

if (cancel == true) 
      { 

      } 

試圖添加break;,但它不適合或因此你不能使用休息;

我該怎麼辦?

謝謝。

+3

使用正確的返回語句 例如:return new List (); – derape

+0

如果你已經寫了一個沒有結局的遞歸函數,那麼你處於危險的領域。遞歸功能只有在退出「策略」已被編入其中時才起作用。使用'return;'語句,代碼需要停止並返回到它的前任(反過來也會調用'return;'等等......) – Flater

+1

......否則你最終會堆棧溢出... –

回答

1

好吧我會發佈一個完整的答案:-)
遞歸函數的問題是,它們是遞歸的。只要你不知道什麼時候該退出,它將永遠運行。
所以你需要的是一個條件來完成它。由於該方法一遍又一遍地調用它自己,因此基本上需要再次調用堆棧並返回事件,正如您在其他任何應返回內容的方法中通常所做的那樣。
一個小例子張貼here 因此,爲了您的退出遞歸循環,你需要一個適當的return語句,返回你所需要的:

if (cancel) 
{ 
    return new List<string>(); 
} 

顯然,你會把你需要到您的列表;-)

一切