2010-06-09 14 views
6

Possible Duplicates:
Exception during iteration on collection and remove items from that collection
How to remove elements from a generic list while iterating around it?
Better way to remove matched items from a list방법을 제대로 목록에서 항목을 제거

// tmpClientList is List<Client> type 

if (txtboxClientName.Text != "") 
    foreach (Client cli in tmpClientList) 
     if (cli.Name != txtboxClientName.Text) 
      tmpClientList.Remove(cli); 

오류 : ". 컬렉션이 수정되었다 열거 작업이 실행되지 않을 수 있습니다"

몇 가지 간단한 방법으로 목록의 항목을 다른 목록이나 배열에 저장하지 않고 코드의 다른 위치에서 항목을 제거하지 않고 목록에서 항목을 제거 할 수 있습니까? 또한 RemoveAt (인덱스)를 시도했지만 루프가 실행될 때 수정되는 것과 정확히 똑같은 상황입니다.

+0

정확한 중복 문제에 동의, 링크 1 참조 http://stackoverflow.com/questions/1154325/better-way-to-remove-matched-items-from-a-list and link two : http : //stackoverflow.com/questions/1541777/can-you-remove-an-item-from-a-list-whilstiterating-through-it-in-c – CrimsonX

답변

1

문제는 foreach 반복에서 목록 수정을 시도하고 있다는 것입니다. for를 for로 바꾸면 괜찮을 것입니다.

또한 이름에 사용자 입력을 사용하는 것 같으므로 여분의 공백을 제거하려면 Trim()을 사용하여 입력을 약간 정리하는 것이 좋습니다. 그렇지 않으면 '존'과 '존'이 서로 다른 두 가지 일을하게됩니다. 초기! = ""확인과 동일합니다.

+0

그 뜻은 ""과 ""가 같은, 그리고 그 상황에서 너무 입력을 잘라야한다 (사용자가 입력 만 흰색 문자를 입력)? – qlf00n

+0

@dygi : 예. 공백을 제거하면 관련 정보 만 남게됩니다.이 경우에는 아무 것도 없습니다. 이런 경우가 발생할 수 있습니다. 사용자가 그 뒤에 공백을 포함하여 이름을 입력하기 시작한 다음 문자를 삭제하기로 결정하면 공백을 볼 수 없기 때문에 문자가 삭제됩니다. – Rox

2

foreach를 사용하지 마십시오. RemoveAt를 사용하여 목록에 사용하고 목록을 내려갑니다 (끝에서 시작). 그래서

,

// tmpClientList is List<Client> type 

if (txtboxClientName.Text != "") 
    foreach (int pos = tmpClientList.Length - 1; pos >= 0; pos--) 
    { 
     Client cli = tmpClientList[pos]; 
     if (cli.Name != txtboxClientName.Text) 
      tmpClientList.RemoveAt(pos); 
    } 
4

중 하나에 대한/루프 동안, 또는 tmpClientList.RemoveAll(a => a.Name == txtboxClientName.Text)를 사용합니다. 사용중인 C# 버전을 지정하지 않으므로 ymmw.

+1

그리고 2.0에 국한 될 때, 그것은 좀 더 장황 해집니다 :'tmpClientList.RemoveAll (delegate (Client a) {return a.Name == txtboxClientName.Text;}); ' – Humberto

11

목록을 거쳐 뒤로 이동합니다. 항목을 제거하면 다음 항목에는 영향을주지 않습니다. List<T>

for(var i=tmpClientList.Count-1;i>=0;i--) 
{ 
    if (tmpClientList[i].Name != txtboxClientName.Text) 
      tmpClientList.RemoveAt(i); 

} 
+0

공유를위한 좋은 간단한 해결책, 덕분에 – qlf00n

11

항목을 제거할지 여부를 나타 내기 위해 대리자를 취하는 RemoveAll 방법이있다. 이처럼 사용할 수 있습니다

tmpCLientList.RemoveAll(cli => cli.Name != txtboxClientName.Text); 
+0

+1 C# 3.0 이상에서만 작동합니다. OP는 버전 2, 3, 4로 태그를 붙였습니다 :-) –

+1

@Jakob : OP가 C# 3 이상을 사용하지 않으면 old-skool 대리자 구문으로'RemoveAll'을 호출 할 수 있습니다 :'tmpCLientList.RemoveAll (Delegate (Client cli) {return cli.Name! = txtboxClientName.Text;}); ' – LukeH

+0

아 맞아. RemoveAll이 확장 메소드라고 생각해. 죄송합니다 그것에 대해 :-) –

1

당신은 당신이 삭제하고 "txtboxClientName"목록에서 항목을 제거 할 수있는 새 목록을 반복 할 항목과 다른 목록을 만들 수 있습니다.

+0

맞아, 내가 원래 하나 이상의 iterating 동안 복사 목록에 대한 Contains() 및 Remove() 메서드를 사용할 수 있습니다. 감사. – qlf00n

1

실제로 foreach는 열거자를 사용하여 주어진 Item-Collections를 반복합니다. System.Collections.Generic.List<T>은 에서 provide a Class까지 구현하며 목록의 항목을 반복하는 방법을 알고 있습니다 (예 : Enumerator). 이제 foreach를 사용하여 해당 목록을 반복 할 경우 열거자는 현재 위치를 추적하고 다음 위치에 도달하는 방법 및 기타 사항을 추적합니다. 내부 논리는 변수 n에 항목 수를 저장 한 다음 0부터 n-1까지 모든 객체에 액세스하는 것과 같을 수 있습니다. Enumerator가 목록의 마지막 개체를 전달하려고 시도 할 때 반복 단계 사이에 개체가 제거되면 알 수 있듯이 NullReferenceException으로 끝납니다. 따라서 반복 실패를 막기 위해 목록 자체는 열거 중에 수정 될 수 없습니다.

희망은 적어도 조금 포괄적으로 말할 수 있었기를 바랍니다. :-)

+0

매우 정확한 정보를 주셔서 감사합니다. GTK는 내부적으로 어떻게 작동합니까? – qlf00n

관련 문제