Programming

Roslyn이 코드를 컴파일하지 못했습니다.

procodes 2020. 8. 26. 20:01
반응형

Roslyn이 코드를 컴파일하지 못했습니다.


프로젝트를 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, 모두 ab확실히 할당됩니다. 동적 타이핑에서 생각 해낼 수있는 이상한 점이 있더라도 a <= bTryParse호출을 모두 평가 한 후에 만 평가할 것으로 기대 합니다.

그러나 연산자와 변환을 통해 까다로워서 충분히 교활하다면 A && B && C평가 A하고 평가 C하지 않는 표현식을 갖는 것이 전적으로 가능하다는 것이 밝혀졌습니다 B. Neal Gafter의 독창적 인 예 Roslyn 버그 보고서참조하세요 .

이 작업을 수행하는 dynamic것은 훨씬 더 어렵습니다. 피연산자가 동적 일 때 관련된 의미는 설명하기가 더 어렵습니다. 오버로드 해결을 수행하려면 어떤 유형이 관련되어 있는지 알아보기 위해 피연산자를 평가해야하는데, 이는 직관적이지 않을 수 있습니다. 그러나 Neal은 컴파일러 오류가 필요함을 보여주는 예제를 다시 제시했습니다. 이것은 버그가 아니라 버그 수정 입니다. 그것을 증명 한 Neal에게 엄청난 찬사를 보냅니다.

컴파일러 설정을 통해 수정할 수 있습니까?

아니요,하지만 오류를 방지하는 대안이 있습니다.

첫째, 동적이되는 것을 막을 수 있습니다. 문자열 만 사용할 것이라는 것을 알고 있다면 범위 변수 (예 :) 유형을 사용 IEnumerable<string> 하거나 지정할 수 있습니다 . 그것이 제가 선호하는 옵션입니다.vstringfrom 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 컴파일러에서 버그 또는 적어도 회귀로 보입니다. 이를 추적하기 위해 다음 버그가 제출되었습니다.

https://github.com/dotnet/roslyn/issues/4509

그 동안 Jon의 탁월한 답변 에는 몇 가지 해결 방법이 있습니다.


버그 리포트를 열심히 공부했기 때문에 직접 설명하려고합니다.


상상은 T에 암시 적 캐스트와 일부 사용자 정의 유형 bool간의 대체 false하고 true,로 시작 false. 컴파일러가 아는 한, dynamic첫 번째 인수 &&는 해당 유형으로 평가 될 수 있으므로 비관적이어야합니다.

그런 다음 코드가 컴파일되도록하면 다음과 같은 일이 발생할 수 있습니다.

  • 동적 바인더가 첫 번째를 평가할 때 &&다음을 수행합니다.
    • 첫 번째 인수 평가
    • 그것은 T암시 적으로 그것을 bool.
    • 아,이므로 false두 번째 인수를 평가할 필요가 없습니다.
    • &&평가 결과를 첫 번째 인수로 만듭니다. (아니요, false어떤 이유로 든 아닙니다 .)
  • 동적 바인더가 두 번째를 평가할 때 &&다음을 수행합니다.
    • 첫 번째 인수를 평가하십시오.
    • 그것은 T암시 적으로 그것을 bool.
    • 아, true그래서 두 번째 인수를 평가하십시오.
    • ... 아 젠장, b할당되지 않았습니다.

요컨대, 변수가 "확실히 할당 됨"또는 "확실히 할당되지 않음"인지 여부뿐만 아니라 " false명령문 이후에 명확하게 할당 됨"또는 "확실히 할당 됨"여부를 알려주는 특별한 "정확한 할당"규칙이 있습니다. true이후 할당 ".

These exist so that when dealing with && and || (and ! and ?? and ?:) the compiler can examine whether variables may be assigned in particular branches of a complex boolean expression.

However, these only work while the expressions' types remain boolean. When part of the expression is dynamic (or a non-boolean static type) we can no longer reliably say that the expression is true or false - the next time we cast it to bool to decide which branch to take, it may have changed its mind.


Update: this has now been resolved and documented:

The definite assignment rules implemented by previous compilers for dynamic expressions allowed some cases of code that could result in variables being read that are not definitely assigned. See https://github.com/dotnet/roslyn/issues/4509 for one report of this.

...

Because of this possibility the compiler must not allow this program to be compiled if val has no initial value. Previous versions of the compiler (prior to VS2015) allowed this program to compile even if val has no initial value. Roslyn now diagnoses this attempt to read a possibly uninitialized variable.


This is not a bug. See https://github.com/dotnet/roslyn/issues/4509#issuecomment-130872713 for an example of how a dynamic expression of this form can leave such an out variable unassigned.

참고URL : https://stackoverflow.com/questions/31961411/roslyn-failed-to-compile-code

반응형