다음과 같은 경고가 표시됩니다.
클로저에서 foreach 변수에 액세스합니다. 다른 버전의 컴파일러로 컴파일하면 다른 동작이 발생할 수 있습니다.
내 편집기에서 다음과 같이 보입니다.

이 경고를 수정하는 방법을 알고 있지만이 경고가 표시되는 이유를 알고 싶습니다.
"CLR"버전에 관한 것입니까? "IL"과 관련이 있습니까?
다음과 같은 경고가 표시됩니다.
클로저에서 foreach 변수에 액세스합니다. 다른 버전의 컴파일러로 컴파일하면 다른 동작이 발생할 수 있습니다.
내 편집기에서 다음과 같이 보입니다.

이 경고를 수정하는 방법을 알고 있지만이 경고가 표시되는 이유를 알고 싶습니다.
"CLR"버전에 관한 것입니까? "IL"과 관련이 있습니까?
답변:
이 경고에는 두 부분이 있습니다. 첫 번째는 ...
클로저에서 foreach 변수에 대한 액세스
... 그것은 그 자체로 유효하지 않지만 언뜻보기에는 반 직관적입니다. 올바른 일을하는 것도 매우 어렵습니다. (아래에 링크 한 기사에서 "유해한"것으로 설명합니다.)
발췌 한 코드는 기본적으로 C # 컴파일러 (C # 5 이전)가 foreach1에 대해 생성하는 것의 확장 된 형식이라는 점에 유의하십시오 .
나는 [다음이] 유효하지 않은 이유를 이해하지 못합니다.
string s; while (enumerator.MoveNext()) { s = enumerator.Current; ...
글쎄, 그것은 구문 적으로 유효합니다. 그리고 루프에서 수행하는 모든 작업이의 값 을 사용하는 s것이라면 모든 것이 좋습니다. 그러나 마무리 s는 반 직관적 인 행동으로 이어질 것입니다. 다음 코드를 살펴보십시오.
var countingActions = new List<Action>();
var numbers = from n in Enumerable.Range(1, 5)
select n.ToString(CultureInfo.InvariantCulture);
using (var enumerator = numbers.GetEnumerator())
{
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
Console.WriteLine("Creating an action where s == {0}", s);
Action action = () => Console.WriteLine("s == {0}", s);
countingActions.Add(action);
}
}
이 코드를 실행하면 다음 콘솔 출력이 표시됩니다.
Creating an action where s == 1
Creating an action where s == 2
Creating an action where s == 3
Creating an action where s == 4
Creating an action where s == 5
이것이 당신이 기대하는 것입니다.
예상치 못한 내용을 보려면 위 코드 바로 뒤에 다음 코드를 실행하세요 .
foreach (var action in countingActions)
action();
다음 콘솔 출력이 표시됩니다.
s == 5
s == 5
s == 5
s == 5
s == 5
왜? 우리는 모두 똑같은 일을하는 5 개의 함수를 만들었 기 때문에 : s(우리가 닫은) 값을 인쇄하십시오 . 실제로는 동일한 기능 ( "인쇄 s", "인쇄 s", "인쇄 s"...)입니다.
우리가 그것들을 사용하기 위해가는 시점에서 그들은 우리가 요구하는 것을 정확하게 수행합니다 : s. 당신의 마지막 알려진 값을 보면 s, 당신은 그것의 것을 볼 수 있습니다 5. 그래서 우리 s == 5는 콘솔에 5 번 인쇄됩니다.
정확히 우리가 요청한 것이지만 우리가 원하는 것은 아닐 것입니다.
경고의 두 번째 부분은 ...
다른 버전의 컴파일러로 컴파일하면 다른 동작이 발생할 수 있습니다.
... 그것입니다. C # 5부터 컴파일러는 .NET을 통해 이러한 일이 발생하지 않도록 "방지"하는 다른 코드를 생성foreach 합니다.
따라서 다음 코드는 다른 버전의 컴파일러에서 다른 결과를 생성합니다.
foreach (var n in numbers)
{
Action action = () => Console.WriteLine("n == {0}", n);
countingActions.Add(action);
}
결과적으로 R # 경고도 생성됩니다. :)
위의 첫 번째 코드 스 니펫은 사용하지 않기 때문에 모든 버전의 컴파일러에서 동일한 동작을 나타냅니다 foreach(대신 C # 5 이전 컴파일러가 수행하는 방식으로 확장했습니다).
CLR 버전입니까?
나는 당신이 여기서 무엇을 요구하고 있는지 잘 모르겠습니다.
Eric Lippert의 게시물에 따르면 변경 사항은 "C # 5"에서 발생합니다. 그래서아마도 .NET 4.5 이상을 대상으로해야합니다. C # 5 이상의 컴파일러를 사용하여 새로운 동작을 가져오고 그 이전의 모든 것은 이전 동작을 가져옵니다.
하지만 명확하게 말하자면 .NET Framework 버전이 아니라 컴파일러의 기능입니다.
IL과 관련이 있습니까?
다른 코드는 다른 IL을 생성하므로 생성 된 IL에 대한 결과가 있습니다.
1 foreach 은 댓글에 게시 한 코드보다 훨씬 더 일반적인 구성입니다. 이 문제는 일반적으로 foreach수동 열거가 아닌를 사용하여 발생합니다 . 그렇기 때문에 foreachC # 5 의 변경 사항 이이 문제를 방지하는 데 도움이되지만 완전히는 아닙니다.
foreach물건은 여기에 질문의 내용에서 비롯됩니다. 다양하고 일반적인 방법으로 일어날 수 있다는 것이 맞습니다.
첫 번째 대답은 훌륭해서 한 가지만 추가하겠다고 생각했습니다.
예제 코드에서 reflectModel에 IEnumerable이 할당 되었기 때문에 경고가 발생합니다. IEnumerable은 열거 할 때만 평가되며, reflectModel을 더 넓은 범위의 항목에 할당하면 열거 자체가 루프 외부에서 발생할 수 있습니다. .
당신이 변했다면
...Where(x => x.Name == property.Value)
...에
...Where(x => x.Name == property.Value).ToList()
그런 다음 reflectModel에 foreach 루프 내에서 명확한 목록이 할당되므로 열거가 루프 외부가 아닌 루프 내에서 확실히 발생하므로 경고를받지 못할 것입니다.