이 코드에서 '컬렉션이 수정되었습니다'가 발생하는 이유는 무엇입니까?


102
var ints = new List< int >( new[ ] {
    1,
    2,
    3,
    4,
    5
} );
var first = true;
foreach( var v in ints ) {
    if ( first ) {
        for ( long i = 0 ; i < int.MaxValue ; ++i ) { //<-- The thing I iterate
            ints.Add( 1 );
            ints.RemoveAt( ints.Count - 1 );
        }
        ints.Add( 6 );
        ints.Add( 7 );
    }
    Console.WriteLine( v );
    first = false;
}

내부 회 for돌이 를 주석 처리하면 , 그것은 분명히 우리가 컬렉션을 변경했기 때문입니다.

이제 주석 처리를 제거하면 왜이 루프에서 두 항목을 추가 할 수 있습니까? 30 분 (펜티엄 CPU에서)처럼 실행하는 데 시간이 걸리지 만 던지지 않으며 재미있는 점은 다음과 같이 출력된다는 것입니다.

영상

약간의 예상 이었지만 우리가 변경할 수 있다는 것을 나타내며 실제로 컬렉션을 변경합니다. 이 문제가 발생하는 이유는 무엇입니까?


2
그 흥미 롭군요. 동작을 재현 할 수는 있지만 내부 루프를 Int.MaxValue에서 100과 같은 값으로 변경하면 불가능합니다
Steve

얼마나 기다렸습니까? int.MaxValue반복 을 완료하는 데 꽤
오랜

1
foreach는 각 루프의 시작 부분에서 컬렉션이 수정되었는지 확인하기 위해 확인한다고 생각하므로 각 루프 내에서 항목을 추가 한 다음 제거해도 오류가 발생하지 않습니다.
Kaz

6
참조 소스 를보고 변경 감지 작동 방식을 확인 하여이 질문에 직접 답할 수 있었을 것 입니다. 모두가 참조 소스도 단지 :) 단어를 확산, 존재 알고있다
크리스토퍼 Currens

2
호기심 때문입니다. 실제 코드에서이 문제가 발생 했습니까?
ken2k 2014

답변:


119

문제는 List<T>수정 사항 을 감지 하는 방법이 버전 필드 유형을 유지하고 int수정 될 때마다 증가한다는 것입니다. 따라서 반복 사이에 목록 에 2 32 개의 수정을 정확히 몇 배로 만든 경우 검색과 관련하여 해당 수정 사항이 보이지 않게 렌더링됩니다. (에서 로 오버플로 되어 결국 초기 값으로 돌아갑니다.)int.MaxValueint.MinValue

코드에 대해 거의 모든 것을 변경하는 경우-2가 아닌 1 개 또는 3 개의 값을 추가하거나 내부 루프의 반복 횟수를 1만큼 줄이면 예상대로 예외가 발생합니다.

(이것은 특정 동작이 아닌 구현 세부 사항이며 매우 드문 경우 버그로 관찰 될 수있는 구현 세부 사항입니다. 그러나 실제 프로그램에서 문제를 일으키는 것을 보는 것은 매우 드문 일입니다.)


5
참고로 관련 소스 코드_version필드가 int.
Lucas Trzesniewski 2014

1
예, for 루프가 완료된 후 _version의 값이 -2가되도록 설정되었습니다. 그런 다음 6과 7을 더하면 0이되고 목록이 수정되지 않은 것처럼 보입니다.
Kaz 2014

4
나는 이것이 "구현 세부 사항"이라고 불러야할지 모르겠습니다. 그 구현 결정의 부작용이 있기 때문에 일어날 것 같지는 않더라도 현실입니다. 사양 (또는 적어도 문서) InvalidOperationException은 실제로 항상 사실이 아닌을 던져야한다고 말합니다 . 물론 이것은 "구현 세부 사항"의 정의에 따라 달라집니다.
ken2k 2014

3
Jon Skeet, 프로그래밍 언어 디자이너입니까? (Google에서 관련 내용을 찾지 못했습니다.) 왜이 지식을 가지고 있는지 궁금합니다. 이 질문은 Stack Overflow의 "파워"를보기위한 약간의 애타게였습니다.
LyingOnTheSky 2014

6
@LyingOnTheSky : 아니요, C # 언어를 따르고 비평하는면에서 언어 디자이너가되는 것을 좋아합니다. 저는 또한 C # 5 표준화를위한 ECMA-334 기술 그룹에 속해 있습니다 ... 그래서 저는 구멍
Jon Skeet
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.