이상한“열거자가 인스턴스화 된 후에 수집이 수정되었습니다”예외

StackOverflow https://stackoverflow.com/questions/844850

  •  20-08-2019
  •  | 
  •  

문제

아마도 누군가가 올바른 방향으로 나를 지적 할 수있을 것입니다.

단순히 수업 링크리스트를 인쇄하는 기능이 있습니다.

    LinkedList<Component> components = new LinkedList<Component>();
    ...
    private void PrintComponentList()
    {
        Console.WriteLine("---Component List: " + components.Count + " entries---");
        foreach (Component c in components)
        {
            Console.WriteLine(c);
        }
        Console.WriteLine("------");
    }

그만큼 Component 객체에는 실제로 관습이 있습니다 ToString() 그렇게 호출 :

    int Id;
    ...
    public override String ToString()
    {
        return GetType() + ": " + Id;
    }

이 기능은 일반적으로 잘 작동하지만 목록에서 약 30 정도 정도의 항목으로 구축 될 때 문제가 발생합니다. PrintcomplentList foreach 진술은 다시 돌아옵니다 InvalidOperationException: Collection was modified after the enumerator was instantiated.

보시다시피 For Loop 내에서 코드를 수정하지 않으며 XNA 환경 내에 있지만 스레드를 명시 적으로 만들지 않았습니다. 콘솔 출력이 프로그램의 전체 속도를 늦추기에 충분히 인쇄물이 빈번하다는 점에 유의해야합니다.

나는 완전히 혼란스러워, 다른 사람이 이것에 빠져 있니?

도움이 되었습니까?

해결책

목록을 조작하는 곳 (예 : 삽입/제거/재 할당 항목)이있을 것으로 보인다. 내 의심은 콜백/짝수 핸들러가 비동기식으로 해고되는 어딘가에있을 것이라는 것입니다 (아마도 XNA의 일부로 페인트 ETC 루프) 및 목록을 편집하는 것 - 본질적 으로이 문제를 경주 조건으로 유발합니다.

이것이 사실인지 확인하려면 목록을 조작하는 장소 주위에 디버그/트레이스 출력을 넣고 (특히 예외 직전) 콘솔 출력과 동시에 조작 코드를 실행하는지 확인하십시오.

private void SomeCallback()
{
   Console.WriteLine("---Adding foo"); // temp investigation code; remove
   components.AddLast(foo);
   Console.WriteLine("---Added foo"); // temp investigation code; remove
}

불행히도, 그러한 것들은 종종 코드를 바꾸기 위해 코드를 변경하기 때문에 이러한 것들이 종종 디버그에 고통 스러워요. Heisenbug).

한 가지 대답은 액세스를 동기화하는 것입니다. 즉 모두 목록을 편집하는 장소는 a를 사용하십시오 lock 전체 작업 주위 :

LinkedList<Component> components = new LinkedList<Component>();
readonly object syncLock = new object();
...
private void PrintComponentList()
{
    lock(syncLock)
    { // take lock before first use (.Count), covering the foreach
        Console.WriteLine("---Component List: " + components.Count
              + " entries---");
        foreach (Component c in components)
        {
           Console.WriteLine(c);
        }
        Console.WriteLine("------");
    } // release lock
}

그리고 당신의 콜백 (또는 무엇이든)에서

private void SomeCallback()
{
   lock(syncLock)
   {
       components.AddLast(foo);
   }
}

특히 "완전한 작업"에는 다음이 포함될 수 있습니다.

  • 카운트를 확인하십시오 그리고 foreach/for
  • 존재를 확인하십시오 그리고 삽입/제거하십시오

(즉, 개인/이산 작업이 아니라 작업 단위)

다른 팁

대신에 foreach, 나는 사용한다 while( collection.count >0) 그런 다음 사용하십시오 collection[i].

이것이 OP와 관련이 있는지 모르겠지만 동일한 오류가 있었고 Google 검색 중에이 스레드를 찾았습니다. 루프에서 요소를 제거한 후 브레이크를 추가하여 해결할 수있었습니다.

foreach( Weapon activeWeapon in activeWeapons ){

            if (activeWeapon.position.Z < activeWeapon.range)
            {
                activeWeapons.Remove(activeWeapon);
                break; // Fixes error
            }
            else
            {
                activeWeapon.position += activeWeapon.velocity;
            }
        }
    }

휴식을 해결하면 "InvalidoperationException : ENUMERATOR가 인스턴스화 된 후 수집이 수정되었습니다."오류가 발생합니다.

사용 Break 방법 일 수 있지만 일련의 작동에 영향을 줄 수 있습니다. 그 경우에 내가 단순히 변환에서하는 일 foreach 전통적으로 for 고리

for(i=0; i < List.count; i++)
{
    List.Remove();
    i--;
}

이것은 아무런 문제없이 작동합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top