2016-01-04 2 views
2

В моем проекте я пытаюсь перебрать значения и вызвать функцию на них. Когда отладка Count говорит мне, что есть 2 значения. Моя функция работает в DispatcherTimerC# для цикла, выходящего после 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, почему это цикл не работает 2 раза, когда счетчик == 2?

+3

«getRemovedAnswers()« случайно »return _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

@pquest. Вы правы, извините. Надеюсь, объяснение будет понятно. – 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 '- вы, вероятно, должны сначала поставить решение и объяснить неправильные подходы позже. Мне лично нравится «копировать» решение намного лучше, чем взломать итерацию, чтобы работать над сборкой, которая была изменена во время итерации. –

Смежные вопросы