C#이 const로 선언 할 수있는 유형 세트를 제한하는 이유는 무엇입니까?

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

  •  22-07-2019
  •  | 
  •  

문제

컴파일러 오류 CS0283 기본 포드 유형 (문자열, 열거 및 널 참조) 만 다음과 같이 선언 할 수 있음을 나타냅니다. const. 이 제한에 대한 이론적 근거에 대한 이론이 있습니까? 예를 들어, intptr과 같은 다른 유형의 const 값을 선언 할 수있어서 좋을 것입니다.

나는 그 개념을 믿는다 const 실제로 C#의 구문 설탕이며 이름의 모든 용도를 문자 그대로 값으로 대체합니다. 예를 들어, 다음 선언이 주어지면 Foo에 대한 참조는 컴파일 시간에 "foo"로 대체됩니다.

const string Foo = "foo";

이것은 돌연변이 형 유형을 배제 할 것이므로, 주어진 유형이 변이할지 여부를 컴파일 시간을 결정하지 않고이 제한을 선택했을 것입니다.

도움이 되었습니까?

해결책

로부터 C# 사양, 10.4 장 - 상수:
(C# 3.0 사양에서 10.4, 온라인 버전에서 10.3)

상수는 상수 값을 나타내는 클래스 멤버입니다 : 컴파일 시간에 계산할 수있는 값.

이것은 기본적으로 리터럴로만 구성된 표현 만 사용할 수 있다고 말합니다. 컴파일러가 해당 실행을 수행 할 수있는 방법이 없으므로 컴파일 시간에 결과를 계산할 수있는 방법이 없기 때문에 모든 방법, 생성자 (순수한 IL 리터럴로 표시 될 수없는)를 사용할 수 없습니다. 또한 메소드를 불변으로 태그하는 방법이 없기 때문에 (예 : 입력과 출력 사이에 일대일 매핑이 있습니다), 컴파일러가 IL을 분석하여 IL을 분석하는 유일한 방법은 입력 매개 변수 이외의 다른 것, 특수 사례는 일부 유형 (intptr)을 처리하거나 모든 코드에 대한 모든 호출을 허용하지 않습니다.

intptr은 예를 들어 값 유형이지만 여전히 구조이며 내장 리터럴 중 하나가 아닙니다. 따라서 intptr을 사용하는 모든 표현식은 intptr 구조에서 코드를 호출해야하며, 이는 일정한 선언에 합법적이지 않은 것입니다.

내가 생각할 수있는 유일한 법적 상수 가치 유형 예제는 단지 그것을 선언함으로써 0으로 초기화되는 예일 것이며, 그것은 거의 유용하지 않습니다.

컴파일러가 상수를 처리/사용하는 방법에 대해서는 코드에서 상수 이름 대신 계산 된 값을 사용합니다.

따라서 다음과 같은 효과가 있습니다.

  • 원래 상수 이름, 클래스가 선언 된 클래스 또는 네임 스페이스에 대한 언급은이 위치에서 코드로 컴파일됩니다.
  • 코드를 디 컴파일하면 코드에 대한 원래의 "참조"가 상수의 원래 "참조"가 상수의 값 만 상수의 값 만 있기 때문에 마법 숫자가 있습니다.
  • 컴파일러는이를 사용하여 불필요한 코드를 최적화하거나 제거 할 수 있습니다. 예를 들어, if (SomeClass.Version == 1), someclass.version의 값이 1 인 경우, 실제로 IF 진술을 제거하고 코드 블록을 실행합니다. 상수의 값이 1이 아닌 경우 전체 IF 진술과 그 블록이 제거됩니다.
  • 상수의 값은 코드로 컴파일되기 때문에 상수에 대한 참조가 아닌 다른 어셈블리의 상수를 사용하여 상수의 값이 변경되어야하는 경우 어떤 식 으로든 컴파일 된 코드를 자동으로 업데이트하지 않습니다 (그렇지 않아야합니다!).

다시 말해, 다음 시나리오와 함께 :

  1. 어셈블리 A, "버전"이라는 상수가 포함되어 있으며 값이 1입니다.
  2. 어셈블리 B는 그 상수에서 어셈블리 A의 버전 번호를 분석하고이를 1과 비교하여 어셈블리에서 작동 할 수 있는지 확인하는 표현식을 포함합니다.
  3. 누군가가 조립 A를 수정하여 상수의 값을 2로 증가시키고 A (B는 아님)를 재구성합니다.

이 경우, 편집 된 형태의 어셈블리 B는 여전히 1과 1의 값을 비교할 것이다. b가 컴파일 될 때 상수는 값 1을 가졌기 때문이다.

실제로, 그것이 어셈블리 B의 어셈블리 A에서 유일한 사용법이라면, 어셈블리 B에 해당 표현식을 포함하는 코드를 실행하는 것은 어셈블리 A를로드하지 않습니다.

따라서 상수는 결코 변하지 않는 것들에만 사용되어야합니다. 미래에 시간이 바뀌거나 다른 모든 어셈블리가 동시에 재건되었음을 보장 할 수없는 가치라면, Readonly 필드는 상수보다 더 적합합니다.

그래서 이것은 괜찮습니다 :

  • public const int32 번호 daysinaweekingregoriancalendar = 7;
  • 공개 const int32 번호 ofhoursinadayonearth = 24;

이것은 아닙니다.

  • 공개 const int32 AgeofProgrammer = 25;
  • public const string nameoflastprogrammerthatModifiedAsSembly = "Joe 프로그래머";

2016 년 5 월 27 일 편집

좋아, 방금 upvote를 얻었으므로 여기서 내 대답을 다시 읽었고 이것은 실제로 약간 잘못되었습니다.

이제 의도 C# 언어 사양 중 내가 위에서 쓴 모든 것입니다. 당신은 문자로 표현할 수없는 것을 사용해서는 안됩니다. const.

하지만 당신은 할 수 있습니까? 글쎄, 그래 ....

봅시다 decimal 유형.

public class Test
{
    public const decimal Value = 10.123M;
}

이 수업이 어떻게 생겼는지 살펴 보겠습니다 진짜 ildasm을 보았을 때 :

.field public static initonly valuetype [mscorlib]System.Decimal X
.custom instance void [mscorlib]System.Runtime.CompilerServices.DecimalConstantAttribute::.ctor(int8, uint8, uint32, uint32, uint32) = ( 01 00 01 00 00 00 00 00 00 00 00 00 64 00 00 00 00 00 ) 

내가 당신을 위해 그것을 분해하겠습니다 :

.field public static initonly

다음에 해당합니다.

public static readonly

맞아요, a const decimal 실제로 a readonly decimal.

여기서 실제 거래는 컴파일러가이를 사용할 것입니다. DecimalConstantAttribute 마법을 일으키기 위해.

이제 이것은 C# 컴파일러로 내가 아는 유일한 마법이지만 언급 할 가치가 있다고 생각했습니다.

다른 팁

이 제한에 대한 이론적 근거에 대한 이론이 있습니까?

그것이 단지 이론이 될 수 있다면, 나의 이론은 원시 유형의 const 값을 MSIL의 문자 그럴 opcode 매개 변수로 표현할 수 있다는 것입니다. 구문은 사용자 정의 유형의 값을 문자 그럴로 표현합니다.

Const의 개념은 실제로 C#의 구문 설탕이며 이름의 모든 용도를 문자 그대로의 가치로 대체한다고 생각합니다.

컴파일러는 다른 언어로 Const 객체로 무엇을합니까?

런타임에 평가 될 변한 유형에 Readonly를 사용할 수 있습니다. 보다 이 기사 차이점을 위해.

컴파일러는 변수를 MSIL의 리터럴 값으로 대체하기 때문에 consts는 c#의 숫자와 문자열로 제한됩니다. 다시 말해서 쓸 때 :

const string myName = "Bruce Wayne";
if (someVar == myName)
{
   ...
}

실제로 처리됩니다

if (someVar == "Bruce Wayne")
{
   ...
}

그리고 네, C# 컴파일러는 문자열에서 평등 연산자 (==)를 처리 할만 큼 똑똑합니다.

string1.Equals(string2)

값 유형만이 상수로 표현 될 수있는 것 같습니다 (문자열을 제외하고 값과 객체 유형 사이의 어딘가에 있음).

나에게는 괜찮습니다 : 물체 (참조)는 힙에 할당되어야하지만 상수는 전혀 할당되지 않습니다 (컴파일 시간에 교체되었으므로).

요컨대, 모든 간단한 유형, 열거 및 줄은 불변이지만 구조물은 그렇지 않습니다. 돌연변이 가능한 상태 (필드, 속성, 참조 유형에 대한 참조)를 가진 구조물을 가질 수 있습니다. 따라서 컴파일러는 (컴파일 시간에) 구조물 변수의 내부 상태를 변경할 수 없음을 확인할 수 없습니다. 따라서 컴파일러는 유형이 정의에 따라 일정한 표현식으로 사용하기에 불변이되지 않도록해야합니다.

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