프로젝트를 VS2013에서 VS2015로 마이그레이션 한 후 프로젝트가 더 이상 빌드되지 않습니다. 다음 LINQ 문에서 컴파일 오류가 발생합니다.
static void Main(string[] args)
{
decimal a, b;
IEnumerable<dynamic> array = new string[] { "10", "20", "30" };
var result = (from v in array
where decimal.TryParse(v, out a) && decimal.TryParse("15", out b) && a <= b // Error here
orderby decimal.Parse(v)
select v).ToArray();
}
컴파일러는 오류를 반환합니다.
오류 CS0165 할당되지 않은 지역 변수 ‘b’사용
이 문제의 원인은 무엇입니까? 컴파일러 설정을 통해 수정할 수 있습니까?
답변
이 문제의 원인은 무엇입니까?
나에게 컴파일러 버그처럼 보입니다. 적어도 그렇습니다. 있지만 decimal.TryParse(v, out a)
및 decimal.TryParse(v, out b)
표현이 동적으로 평가, 내가 예상 컴파일러는 여전히 이해가가 도달하는 시간으로 a <= b
, 모두 a
와 b
확실히 할당됩니다. 동적 타이핑에서 생각 해낼 수있는 이상한 점이 있더라도 a <= b
두 TryParse
호출을 모두 평가 한 후에 만 평가할 것으로 기대 합니다.
그러나 연산자와 변환을 통해 까다로워서 충분히 교활하다면 A && B && C
평가 A
하고 평가 C
하지 않는 표현식을 갖는 것이 완전히 가능하다는 것이 밝혀졌습니다 B
. Neal Gafter의 독창적 인 예 는 Roslyn 버그 보고서 를 참조하세요 .
이 작업을 수행하는 dynamic
것은 훨씬 더 어렵습니다. 피연산자가 동적 일 때 관련된 의미는 설명하기가 더 어렵습니다. 왜냐하면 오버로드 해결을 수행하려면 어떤 유형이 관련되어 있는지 알아보기 위해 피연산자를 평가해야하는데, 이는 직관적이지 않을 수 있습니다. 그러나 Neal은 컴파일러 오류가 필요함을 보여주는 예제를 다시 제시했습니다. 이것은 버그가 아니라 버그 수정 입니다. 그것을 증명 한 Neal에게 엄청난 찬사를 보냅니다.
컴파일러 설정을 통해 수정할 수 있습니까?
아니요,하지만 오류를 방지하는 대안이 있습니다.
첫째, 동적이되는 것을 막을 수 있습니다. 문자열 만 사용할 것이라는 것을 알고 있다면 범위 변수 에 (예 🙂 유형을 사용 IEnumerable<string>
하거나 지정할 수 있습니다 . 그것이 제가 선호하는 옵션입니다.v
string
from string v in array
당신이 경우 정말 그것을 동적를 계속해야, 단지 줄 b
로 시작하는 값을 :
decimal a, b = 0m;
이것은 아무런 해를 끼치 지 않을 것입니다. 실제로 동적 평가가 미친 짓을하지 않는다는 것을 알고 있으므로 b
사용하기 전에 값을 할당 하여 초기 값을 무의미하게 만듭니다.
또한 괄호 추가도 작동하는 것 같습니다.
where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b)
이는 다양한 오버로드 해결이 트리거되는 지점을 변경하고 컴파일러를 행복하게 만듭니다.
이 하나 여전히 남아있는 문제 일 -와 명확한 과제에 대한 사양의 규칙 &&
운영자 필요성은 때에만 적용한다는 것은 명확히하는 &&
연산자는 두과의 “일반”구현에 사용되는 bool
피연산자. 다음 ECMA 표준을 위해 이것이 수정되었는지 확인하려고 노력할 것입니다.
답변
이것은 Roslyn 컴파일러에서 버그 또는 적어도 회귀로 보입니다. 이를 추적하기 위해 다음 버그가 제출되었습니다.
그 동안 Jon의 탁월한 답변 에는 몇 가지 해결 방법이 있습니다.
답변
버그 리포트를 열심히 공부했기 때문에 직접 설명하려고합니다.
상상은 T
에 암시 적 캐스트와 일부 사용자 정의 유형 bool
간의 대체 false
하고 true
,로 시작 false
. 컴파일러가 아는 한 dynamic
첫 번째 인수 &&
는 해당 유형으로 평가 될 수 있으므로 비관적이어야합니다.
그런 다음 코드가 컴파일되도록하면 다음과 같은 일이 발생할 수 있습니다.
- 동적 바인더가 첫 번째를 평가할 때
&&
다음을 수행합니다.- 첫 번째 인수 평가
- 그것은
T
암시 적으로 그것을bool
. - 아,이므로
false
두 번째 인수를 평가할 필요가 없습니다. &&
평가 결과를 첫 번째 인수로 만듭니다. (아니요,false
어떤 이유로 든 아닙니다 .)
- 동적 바인더가 두 번째를 평가할 때
&&
다음을 수행합니다.- 첫 번째 인수를 평가하십시오.
- 그것은
T
암시 적으로 그것을bool
. - 아,
true
그래서 두 번째 인수를 평가하십시오. - … 아 젠장,
b
할당되지 않았습니다.
요컨대, 변수가 “확실히 할당”되었는지 또는 “확실히 할당되지 않았는지”뿐만 아니라 ” false
문 뒤에 명확하게 할당”또는 “확실히 할당되었는지”를 알려주는 특별한 “정확한 할당”규칙이 있습니다. true
문 이후 할당 “.
이것들은 &&
and ||
(and !
and ??
and ?:
)를 처리 할 때 컴파일러가 복잡한 부울 표현식의 특정 분기에 변수가 할당 될 수 있는지 여부를 검사 할 수 있도록 존재합니다.
그러나 표현식의 유형이 boolean으로 유지되는 동안에 만 작동 합니다 . 표현의 한 부분 인 경우 dynamic
(또는 부울이 아닌 정적 유형) 우리는 더 이상 안정적으로 발현이라고 말할 수 있습니다 true
또는 false
– 다음 번에 우리가 캐스팅 bool
소요되는 지점을 결정, 그것의 마음을 변경되었을 수 있습니다.
업데이트 : 이제이 문제 가 해결 되고 문서화 되었습니다 .
동적 표현식에 대해 이전 컴파일러에 의해 구현 된 명확한 할당 규칙은 확실히 할당되지 않은 변수를 읽을 수있는 코드의 경우를 허용했습니다. 이에 대한 보고서는 https://github.com/dotnet/roslyn/issues/4509 를 참조 하십시오 .
…
이러한 가능성 때문에 컴파일러는 val에 초기 값이없는 경우이 프로그램이 컴파일되는 것을 허용하지 않아야합니다. 이전 버전의 컴파일러 (VS2015 이전)에서는 val에 초기 값이없는 경우에도이 프로그램을 컴파일 할 수있었습니다. Roslyn은 이제 초기화되지 않은 변수를 읽으려는이 시도를 진단합니다.
답변
이것은 버그가 아닙니다. 이 양식의 동적 표현이 이러한 out 변수를 할당되지 않은 상태로 둘 수있는 방법에 대한 예제는 https://github.com/dotnet/roslyn/issues/4509#issuecomment-130872713 을 참조 하십시오 .