2012-09-07 2 views
1

컬렉션의 모든 요소를 ​​제거하려고했는데 이후로 .RemoveAll이 표시되지 않았거나 아래 코드로갔습니다.System.Collections.IEnumerator 개체의 예기치 않은 동작

int number = addressBook.Items.Count; 
System.Collections.IEnumerator enumerator = ... 
while (enumerator.MoveNext()) 
{ 
    target = enumerator.Current as Outlook.ContactItem; 
    target.Delete(); 
} 

그러나 컬렉션의 나머지 요소 수는 대략 프로그램 실행마다 절반이라고 나타났습니다. 내 결론은 .Delete()은 다음 요소로 건너 뜁니다. 즉, .MoveNext()은 루프의 조건이 인 다음 다음으로 건너 뜁니다.

그래서 열거자를 다음과 같이 재설정하려고했습니다. I는 .Count 체크로

int number = addressBook.Items.Count; 
System.Collections.IEnumerator enumerator = ... 
while (enumerator.MoveNext()) 
{ 
    target = enumerator.Current as Outlook.ContactItem; 
    target.Delete(); 
    enumerator.Reset(); 
} 

단, I는 마지막 요소가 삭제 된 후 남아있는 요소들의 수가 계속 한 것을보고하고 열거 리셋되고. 그리고 물론 예외가 생겼습니다.

이 사진에는 무엇이 있습니까? 나는 일 전에보고되고 해결 될 것이기 때문에 버그가 아니라는 것을 알고 있습니다 ...

+0

단순히 'foreach' 루프를 사용하지 않는 이유는 무엇입니까? – Jon

+0

수를 어떻게 확인합니까? – Tigran

+0

@ 존 당신이 그것에 대해 생각하는 것은 컬렉션이 아닙니다. 그것은 아웃룩 이야기입니다. 나는 연락처를 제거하려고하는데 그것은 나를 싸워. –

답변

1

두 가지.

  1. 각 항목을 삭제 한 후에 다시 인스턴스화하는 한 열거자를 사용하여 모든 항목을 삭제할 수 있어야합니다.LINQ를 사용하여, 그것과 같아야합니다 MSDN에 따르면

    while (addressBook.Items.Count > 0) 
    { 
        addressBook.Items 
         .OfType<Outlook.ContactItem>() 
         .Last() 
         .Delete(); 
    } 
    
  2. , 실제로 마지막로 시작하는 항목 삭제해야 : 나는 기대 http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._contactitem.delete.aspx

+0

위대한 링크가 있지만 그 방법의 일관성에 의문을 제기합니다. 마지막 개체를 먼저 삭제해야하는 이유는 무엇입니까? 나는 하나의 연락처 만 삭제하고 다음 날에는 하나만 삭제할 필요가 있다고 가정합니다. ** 모든 ** 연락처 ** 산만 ** 설명 된 방법에 따라 ** 여전히 ** 수행 중입니다. 유효한 연산. 그렇다면 왜 ** 그 길을 귀찮게합니까? 나는 논리적으로 맞습니까? 아니면 제가 놓친 것이 있습니까? 그리고 .First()는 .Last()보다 조금 더 빨라야한다고 생각합니다. –

+0

@KonradViltersten 동의합니다. Office 2007에 대한 설명서를 보면 MSDN에 대한 권장 사항이 없습니다 (필자가 제공 한 링크는 Office 2010 임). 그래서 그것은 최근의 것입니다. 단지 기존의 것들이 아닙니다. –

1

Marc Gravell's Answer을 참조하십시오.

재설정은 중복됩니다. 그래서 iterator 블록이 Reset시에 예외를 throw하는 것이 언어 사양의 에서 요구된다. 올바른 작업은 단순히 이전 반복기 인 을 처리하고 해제 한 다음 GetEnumerator를 다시 호출하는 것입니다. 또는 더 나은 방법 : 모든 데이터가 반복 가능하지 않으므로 을 두 번 읽지 않아도됩니다.

은 다음 링크를 참조하십시오

Can't add/remove items from a collection while foreach is iterating over it
When IEnumerator.Reset() method is called?

using IEnumerator to removing items

희망이 도움이 ..

3
있는 IEnumerator는 기본 수집 유물로만 한 사용할 수 있습니다

변경되지 않았습니다.. 그것이 변경되면 (예 : 요소를 제거하여) 열거자는 무의식적으로 무효화됩니다.

컬렉션을 수정하는 동안 하나의 열거자를 사용하여 컬렉션을 탐색 할 수는 없으며 재설정이 도움이되지 않습니다. 매번 새로운 열거자를 생성하면됩니다. 예 : 그런 일이 가능할 수도 있습니다.

while (addressBook.Items.Count > 0) 
{ 
    foreach(Outlook.ContactItem target in ...) 
    { 
     target.Delete(); 
     break; // <-- ! 
    } 
} 
+1

또는 linq :'while (addressBook.Items.Count> 0) addressBook.Items.OfType (). 처음(). 삭제();' –

+0

@KooKiz LINQ- 마술은 효과가 있지만 나는 강력하게 ** 자신이 컬렉션을 반복 할 필요가 있다는 것에 싫어한다. 코드를 답으로 써 사람들이 등급을 매길 수 있도록하라. 그리고 발견 한 링크와 결합하십시오. 나는 그것을 찾고 있었지만 놓쳤을 것입니다. 현재 InterOp 및 Outlook으로 Grrr. :) –

1

을 그 Enumerable.Reverse 확장을 사용 while...Last().Delete() 솔루션을 개선 할 것입니다. 다음과 같이 그 보일 수 있습니다 무엇 : 나는 종종 Reverse를 사용하지 않는

foreach(var target in addressBook.Items 
    .OfType<Outlook.ContactItem>() 
    .Reverse()) 
{ 
    target.Delete(); 
} 

; 사실, 프로덕션 코드에서이 코드를 사용하는 것을 기억하지는 않지만 Outlook과 상호 운용하지 않아도됩니다. 여기서 이점은 while...Last().Delete() 메서드와 같은 각 항목 삭제 후 목록의 나머지 부분을 반복적으로 탐색하지 않는다는 것입니다. 항목 목록이 작을 때 성능에 별다른 차이가 없을 수 있지만 탐색이 비싸면 (또는 COM iterop 호출에 해당 될 가능성이 있기 때문에) 또는 목록이 큰 경우 성능 차이가 클 수 있습니다. 확실히 알 수있는 유일한 방법은/프로필을 테스트하는 것입니다.

+0

동시에 변경하는 컬렉션을 'foreach'할 수 있습니까? 또한 나는 MS가이 문제에 잘못되었다고 생각하며 마지막 첫 부분의 제거는 오해라고 생각합니다. 그렇지 않으면 첫 번째 요소를 제거하는 것이 유효하지 않으며 모든 요소가 사라질 때까지 새로운 첫 번째 요소 등을 삭제합니다. 절대로 "역방향"의 멋진 사용법. 나는 실제로 그것을 실제로 본 적이 없다.나에게 어떤 수수께끼가 나는가? ** 질문 **을이 흥미로운 질문으로 체크 했는데도 많은 대답이 있었지만 ... ** –

+0

'Reverse '에 대한 반복자는 반복하기 전에 모든 것을 읽는다. 'ICollection' 열거) - 일반적으로 나는 당신이 맞다고 말할 것입니다. 에 관계없이, 그것을 고치기 위해서 당신이해야 할 일은 반복하기 전에'ToList'를 호출하는 것입니다. 그러면 원래의 IEnumerable 인스턴스가 아닌리스트 인스턴스를 반복 할 것입니다. – devgeezer

+0

@ KonradViltersten, 저는 여러분의 샘플에서'GetEnumerator ... while (enumerator.MoveNext()) '가'foreach' 루프를 사용하는 것과 같은 논리적 거리라고 언급하지 않았습니다. (foreach는 루프가 종료됩니다.) – devgeezer