2016-01-04 80 views
2

在我的項目中,我嘗試循環使用值並在其上調用函數。調試Count時告訴我有2個值。我的功能在DispatcherTimer運行c#for循環在1個循環後退出

我在構造器:

DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer(); 
dispatcherTimer.Tick += new EventHandler(runSync); 
dispatcherTimer.Interval = new TimeSpan(0, 0, syncTime); 
dispatcherTimer.Start(); 

我的功能

private void runSync(object sender, EventArgs e) 
{ 

    //I can see the value of count is 2 when using break points 
    List<string> vals = repo.getRemovedAnswers(); 
    for (int i = 0; i < vals.Count(); i ++) 
    { 
     //i do something with the element in my database 

     // send back a confirmation that the delete is finished 
     repo.setAnswerDeleted(vals.ElementAt(i)); 
     Console.WriteLine(i + " removed"); 
     // 
    }    
    Console.WriteLine("syncing"); 

} 

功能在我的回購類setAnswerDeleted,它是一種無效的方法所以沒有返回休息或任何東西。

public List<String> getRemovedAnswers() 
{ 
    return _answersRemoved; 
} 

public void setAnswerDeleted(string uniqueIdAnswer) 
{ 
    _answersRemoved.RemoveAll(item => item == uniqueIdAnswer); 

} 

在日誌中我可以看到環運行,每dispatchtimer週期和酮基調用該方法1的時候,爲什麼for循環沒有運行2倍時計數== 2?

+3

'getRemovedAnswers()'是否有機會返回_answersRemoved;'?然後,您將從正在迭代的同一列表中刪除元素。 –

+0

@AlexD它是,但它會改變vals的值嗎?它在不同的類dosnt它複製? –

+1

@SvenB不,它是對同一個列表的引用。 –

回答

4

嘗試改變這樣的代碼:

private void runSync(object sender, EventArgs e) 
{ 
    //I can see the value of count is 2 when using break points 
    List<string> vals = repo.getRemovedAnswers(); 
    for (int i = vals.Count() - 1; i >= 0; i--) 
    { 
     repo.setAnswerDeleted(vals.ElementAt(i)); 
     Console.WriteLine(i + " removed"); 
    // 
    }    
    Console.WriteLine("syncing"); 

} 

您的迭代一次,因爲你通過一個從列表中刪除元素和增量索引,但是之後刪除的元素previus長度 - 1,因此下一次檢查vals.Count()會返回1,您的索引是1.這樣,您的索引將從1開始,在第二步中將爲0.

+1

你應該解釋你爲什麼做了改變 – pquest

+0

@請求你是對的,對不起。我希望這個解釋是可以理解的。 – erikscandola

+1

注意:雖然這解決了問題,但它突出了返回引用可變內部列表的問題。如果'GetRemovedAnswers'方法有機會被代碼的原始作者使用,那麼返回列表的副本可能會更好。 –

2

問題是您正在修改列表,重複遍歷它,因此它將刪除元素,並且Count()結果正在每個循環中下移。最佳做法是返回列表的副本,以便在您不去時修改它。

List<string> getRemovedAnswers() 
{ 
    .. logic 
    List<string> previousReturn = ... 
    return new List<string>(previousReturn);// Creates new list 
} 

另一種很好的做法是使用,而不是通過索引去一個foreach循環。

foreach(var element in vals) 
{ 
    repo.setAnswerDeleted(element); 
} 

如果你這樣做了,它會拋出一個異常,說該集合在迭代時被修改過。這會馬上提醒你這個問題。

+0

複製列表不是一個好主意。對於兩個元素沒有問題,但... – Steve

+0

@Steve它沒有複製列表中的項...... –

+0

正如你所說的第一個樣本根本不工作,因爲'vals'被setAnswerDeleted ' - 你可能應該先解決方案,然後再解釋錯誤的方法。我個人喜歡「複製」解決方案比黑客迭代更好地處理迭代期間修改的集合。 –