정적 읽기 전용 대 const


1386

에 대한 conststatic readonly필드를 읽었습니다 . 상수 값만 포함하는 클래스가 있습니다. 우리 시스템의 다양한 것들에 사용됩니다. 따라서 내 관찰이 올바른지 궁금합니다.

이러한 종류의 상수 값은 항상 static readonly공개 된 모든 것이 어야합니까 ? const내부 / 보호 / 개인 값 에만 사용 합니까?

추천 메뉴가 무엇인가요? static readonly필드를 사용하지 말고 속성을 사용해야합니까?


5
방금 찾은 매우 흥미로운 단일 사례는 다음과 같습니다 static readonly. 내부에서 const를 사용 IEnumerator하면 복구 할 수없는 트리거가 발생하여 yield"내부 컴파일러 오류"가 두려워 집니다. Unity3D 외부에서 코드를 테스트하지는 않았지만 이것이 모노 또는 .NET 버그라고 생각 합니다. 그것은이다 C #을 그럼에도 불구하고 문제가있을 수 있습니다.
cregox


8
또 다른 차이점은 스위치에서 const 문자열을 사용할 수 있지만 정적 읽기 전용 문자열은 사용할 수 없다는 것입니다.
flagg19

7
static readonly변수 로 switch-case문장 에서 사용될 수 없습니다 .이 목적을 위해 필요합니다. caseconst
Mostafiz Rahman

3
static readonly속성 매개 변수로도 사용할 수 없습니다
Dread Boy

답변:


940

public static readonly필드는 조금 이례적입니다. public static속성 ( get) 만 더 일반적 일 것입니다 (아마도 private static readonly필드로 지원).

const값은 호출 사이트에 직접 레코딩됩니다. 이것은 양날입니다.

  • 런타임에 값을 가져 오면 쓸모가 없습니다. 아마도 설정에서
  • const 값을 변경하면 모든 클라이언트를 다시 작성해야합니다.
  • 그러나 메소드 호출을 피하기 때문에 더 빠를 수 있습니다 ...
  • ... 어쨌든 JIT에 의해 때때로 인라인되었을 수 있습니다.

값이 절대로 변하지 않으면 const는 괜찮습니다.-const는 Zero합리적입니다 .p 그 외에는 static속성이 더 일반적입니다.


13
왜 필드 위에 속성이 있습니까? 불변의 클래스라면 아무런 차이가 없습니다.
Michael Hedgpeth 2009

73
@Michael-항상 같은 이유; 구현을 숨 깁니다. 게으른로드, 구성 기반, 외관 또는 기타 사항이 필요할 수 있습니다. 실제로, 어느 쪽이든 종종 괜찮을 것입니다 ...
Marc Gravell

42
@CoffeeAddict 정의에 따르면 상수 구성 파일에서 값을 가져 오지 않습니다 . 컴파일 타임에 리터럴로 레코딩됩니다. 런타임에 상수 사용할 수있는 유일한 방법 은 필드를 리플렉션하는 것입니다. 당신이 그것을 사용하려고 할 때마다, 컴파일러 는 문자 그대로의 사용을 위해 당신의 상수 사용을 이미 대체했습니다 . 즉, 코드의 메소드가 6 개의 상수를 사용하고이를 IL로 검사하는 경우 상수 조회에 대한 언급은 없습니다. 리터럴 값은 단순히 현장에로드됩니다
Marc Gravell

37
@MarcGravell-주의 : readonly필드는 switch / case 문에 사용할 수 없으며 대신 필드를 사용해야합니다 const.
Luciano

7
@didibus 필드를 속성으로 변경하면 실제로 API가 중단됩니다. C #의 필드는 변수처럼 효과적으로 작동하는 반면 C #의 속성은 getter 메서드 및 / 또는 setter 메서드를 작성하는 구문 도우미입니다. 이 차이는 다른 어셈블리가 관련 될 때 중요합니다. 필드를 속성으로 변경하고 다른 어셈블리가이 필드에 종속 된 경우 다른 어셈블리를 다시 컴파일해야합니다.
Stephen Booher

237

소비자 가 다른 어셈블리에있는 static readonly경우 사용 합니다 . 데 와 소비자 두 개의 서로 다른 어셈블리 것은 좋은 방법입니다 스스로 발을 쏠 .const


5
따라서 일부 사람들이 언급했거나 암시 한 것처럼 실제로 알려진 상수 값에 대해 const 만 사용하는 것이 현명 할 수 있습니다. 그렇지 않으면 내부, 보호 또는 개인 액세스 범위를 위해 예약해야합니다.
jpierson

1
@Dio 여전히 존재하는 이유는 그 자체가 문제가 아니기 때문입니다. 알아 두어야 할 것이지만 어셈블리 경계를 가로 질러 const를 인라인하는 기능은 성능에 좋은 것입니다. "일정한"은 "변하지 않을 것"을 의미한다는 것은 정말로 이해하는 문제입니다.
Michael Stum

1
@MichaelStum Ok "문제"라고 부르지 말아야합니다. 작업 라인에서 const를 가지고 여러 어셈블리에서 공유하지만 각 배포 또는 코드 배송마다 다시 컴파일합니다. 그럼에도 불구 하고이 사실은 그것을 주목할 가치가 있습니다.
Dio Phung

1
따라서 일반적으로 internal const또는 public static readonly원하는 가시성에 따라 다릅니다.
Iiridayn

2
@Iiridayn 그래, 그것을 보는 나쁜 방법이 아닙니다. 고려해야 할 몇 가지 간결한 사례가 있으며 (예 : 리플렉션을 사용하는 경우 또는 속성에 값이 필요한 경우) public const표준의 일부 (예 : 표준의 일부)에 대한 올바른 용도 가 있습니다. XML로 작업 할 때마다 네임 스페이스 파일은 여러 개로 구성 public const string됩니다.) 일반적으로 public const의미를 제대로 고려한 후에 만 ​​사용해야합니다.
Michael Stum

199

주목할만한 몇 가지 더 관련 사항 :

const int a

  • 초기화해야합니다.
  • 초기화는 컴파일 타임에 있어야합니다 .

읽기 전용 int a

  • 초기화하지 않고 기본값을 사용할 수 있습니다.
  • 런타임에 초기화를 수행 할 수 있습니다 (편집자 : 생성자 내에서만).

39
내에서 ctor.
Amit Kumar Ghosh

1
생성자 내뿐만 아니라 선언에서도 ( docs.microsoft.com/en-us/dotnet/csharp/language-reference/… ).
deChristo

176

이것은 다른 답변에 대한 보충 일뿐입니다. 나는 그것들을 반복하지 않을 것이다 (현재 4 년 후).

a const와 non-const가 다른 의미를 갖는 상황이 있습니다 . 예를 들면 다음과 같습니다.

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

True반면에 출력 :

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

씁니다 False.

그 이유는 메소드 x.Equals에 두 개의 과부하가 있기 때문입니다 . 하나는 short( System.Int16)를 사용하고 다른 하나는 object( System.Object)를 사용합니다. 이제 문제는 하나 또는 둘 다 내 y주장에 적용되는지 여부 입니다.

경우 y(리터) 컴파일 시간 상수는 상기 const케이스는, 거기 암시 적 변환이 존재하는 것이 중요해진다 로부터 int short (가)가 제공 int정수이며, 단, 그 값이 범위 내에 있는지 C # 컴파일러를 확인한다 short( 이는 42임). C # 언어 사양의 암시 적 상수 식 변환 을 참조하십시오 . 따라서 두 가지 과부하를 모두 고려해야합니다. 과부하 Equals(short)가 선호됩니다 (모두 shortobject이지만 모두 object는 아닙니다 short). 따라서 y로 변환되고 short과부하가 사용됩니다. 그런 다음 동일한 값의 Equals두 개 short를 비교 하면 true.

y상수가 아닌, 어떤 암시 의 변환 int에는 short존재하지 않는다. 이는 일반적으로 int에 맞지 않을 정도로 너무 클 수 있기 때문입니다 short. ( 명시적인 변환은 존재하지만 나는 말하지 않았 Equals((short)y)으므로 관련이 없습니다.) 우리는 과부하가 하나만 적용되는 것을 볼 수 Equals(object)있습니다. 그래서 y에 박스입니다 object. 그런 다음 Equalsa System.Int16와 a 를 비교 System.Int32하고 런타임 유형이 동의하지 않기 때문에 결과가됩니다 false.

우리는 일부 (드문) 경우에 const유형 멤버를 static readonly필드로 변경 하거나 가능한 경우 다른 방법으로 프로그램의 동작을 변경할 수 있다고 결론을 내립니다 .


17
허용되는 답변에 추가하십시오. 데이터 형식과 다른 유사한 지침 (시도 캐치 등과 같은)의 적절한 변환은 숙련 된 프로그래머의 필수 요소이며 컴파일러에 맡겨서는 안된다고 덧붙이고 싶습니다. 그럼에도 불구하고 나는 여기서 새로운 것을 배웠다. 감사합니다.
Uknight

와우, 나는 C #으로 오랫동안 프로그래밍 해 왔으며 short 범위 내의 const int가 암시 적으로 short로 변환 될 수 있다고 추측하지 않았을 것입니다. 나는 그것이 다소 이상하다고 말해야한다. 나는 C #을 좋아하지만 많은 가치를 추가하지는 않지만 끊임없이 고려하는 데 필요한 두뇌 능력을 많이 추가하는 이상한 불일치가 특히 초보자에게 성 가실 수 있습니다.
Mike Marynowski

@MikeMarynowski 충분합니다. 그러나 나는 그들이 다른 이유 중에서도 그 진술을 short x = 42;합법화 하기 위해 그 규칙을 만들었다 고 생각 합니다. 거기에 int, 즉 리터럴 이 있기 때문에 42묵시적으로로 바뀝니다 short x. 그러나 그들은 이것을 숫자 리터럴로 제한했을 수도 있습니다. 그러나 그들은로 정의 된 short x = y;곳 과 같은 것을 허용하기로 결정 했으며 결국 이것으로 끝났습니다. yconst int y = 42;
Jeppe Stig Nielsen

87

참고로 한 가지가있다 CONST (예외가 문자열 인) 원시적 / 값 유형으로 제한됩니다


30
사실 const너무 다른 유형에 사용될 수 있습니다, 그것은 쓸모 :) 만드는, 그것은 null로 초기화되어야한다는 점을 제외하고
nawfal

6
에서와 같은 예외 System.Exception? :)
Memet Olsen

4
보다 구체적 @nawfal 유일한 값 유형 에 대한이 const사용될 수있다 sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, 및 모든 enum유형. 또는 또는 const같은 다른 값 유형에는 사용할 수 없습니다 . 또한 구조체 에는 사용할 수 없습니다 (일부에서는 "프리미티브"유형으로 간주됩니다. 프리미티브 유형이라는 용어는 C #에서 혼동됩니다). ↵↵ 모든 참조 유형에 사용할 수 있습니다 . 유형이 인 경우 모든 문자열 값을 지정할 수 있습니다. 그렇지 않으면 값은이어야합니다 . DateTimeTimeSpanBigIntegerIntPtrconststringnull
제프 스티 그 닐슨

@JeppeStigNielsen- 최근 에 이것에 대해 servy논쟁있었는데 그는를 사용하여 무엇이든 (값과 참조 유형) 만들 수 있다고 지적했습니다 . 위해 유형이 기본값으로 설정 한 모든 회원들과 인스턴스입니다. constdefaultstruct
Wai Ha Lee

28

정적 읽기 전용 : static런타임시 생성자를 통해 값을 변경할 수 있습니다 . 그러나 멤버 함수를 통해서는 아닙니다.

상수 : 기본적으로 static. 어디에서나 값을 변경할 수 없습니다 (Ctor, Function, runtime 등).

읽기 전용 : 런타임시 생성자를 통해 값을 변경할 수 있습니다. 그러나 멤버 함수를 통해서는 아닙니다.

내 repo : C # 속성 유형을 살펴볼 수 있습니다 .


1
나쁜 소식은 ... 끊어진 링크!
Fer R


좋은 발췌문 시암 ভাই :)
Muhammad Ashikuzzaman

25

readonly키워드는 다른 const키워드. const필드는 필드의 선언에서 초기화 할 수 있습니다. readonly필드는 선언이나 생성자에 하나 초기화 할 수 있습니다. 따라서 readonly사용 된 생성자에 따라 필드의 값이 다를 수 있습니다. 또한 const필드는 컴파일 타임 상수이지만 readonly런타임 상수에 필드를 사용할 수 있습니다

여기서 짧고 명확한 MSDN 참조


16

constreadonly유사하지만 정확히 동일하지 않습니다.

const필드는 그 값은 컴파일 시간에 계산 될 수 있다는 것을 의미 컴파일 시간 상수이다. readonly필드는 몇 가지 코드 유형의 건설 기간 동안 실행해야하는 추가 시나리오를 가능하게한다. 시공 후 readonly필드를 변경할 수 없습니다.

예를 들어, const멤버를 사용하여 다음과 같은 멤버를 정의 할 수 있습니다.

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

3.14 및 0과 같은 값은 컴파일 타임 상수이므로 그러나 유형을 정의하고 일부 사전 팹 인스턴스를 제공하려는 경우를 고려하십시오. 예를 들어, Color 클래스를 정의하고 Black, White 등과 같은 일반적인 색상에 "상수"를 제공 할 수 있습니다. 오른쪽이 컴파일 타임 상수가 아니기 때문에 const 멤버를 사용하여이 작업을 수행 할 수 없습니다. 일반 정적 멤버 로이 작업을 수행 할 수 있습니다.

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red   = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

그러나 색상의 클라이언트가 흑백 값을 교환하여 색상 클라이언트를 막을 수있는 것은 없습니다. 말할 것도없이, 이것은 Color 클래스의 다른 클라이언트들에게 혼란을 야기 할 것입니다. "읽기 전용"기능은이 시나리오를 해결합니다.

readonly선언에 키워드 를 간단히 도입함으로써 유연한 초기화를 유지하면서 클라이언트 코드가 혼동되지 않도록합니다.

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red   = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

const 멤버는 항상 정적 인 반면, readonly 멤버는 일반 필드처럼 정적 일 수도 있고 그렇지 않을 수도 있습니다.

이 두 가지 목적으로 단일 키워드를 사용할 수 있지만 버전 문제 또는 성능 문제가 발생합니다. 우리가 이것을 위해 하나의 키워드를 사용했다고 가정하고 개발자는 다음과 같이 썼습니다.

public class A
{
    public static const C = 0;
}

다른 개발자가 A에 의존하는 코드를 작성했습니다.

public class B
{
    static void Main() => Console.WriteLine(A.C);
}

이제 생성 된 코드가 AC가 컴파일 타임 상수라는 사실에 의존 할 수 있습니까? 즉, AC 사용을 단순히 값 0으로 대체 할 수 있습니까? "예"라고 대답하면 A 개발자가 AC 초기화 방식을 변경할 수 없음을 의미합니다. 이는 A 개발자의 권한을 무단으로 묶습니다.

이 질문에 "아니오"라고 말하면 중요한 최적화가 빠집니다. 아마도 A의 저자는 AC가 항상 0 일 것이라고 긍정적입니다. const와 readonly를 모두 사용하면 A 개발자가 의도를 지정할 수 있습니다. 따라서 버전 관리 동작이 향상되고 성능이 향상됩니다.


12

필자는 가능한 한 const 를 사용 하는 것이 좋으며, 위에서 언급 한 것처럼 리터럴 표현식이나 평가가 필요없는 것으로 제한됩니다.

그 한계에 부딪 치면 한 가지 경고와 함께 정적 읽기 전용으로 대체됩니다 . 나는 일반적으로 게터와 공공 정적 속성과 백업을 사용하는 것이 개인 정적 읽기 전용 마크가 언급으로 필드를 여기에 .


7

Const : Const는 "constant"일 뿐이며 값은 일정하지만 컴파일 타임에 변수입니다. 그리고 값을 할당해야합니다. 기본적으로 const는 정적이며 전체 프로그램에서 const 변수의 값을 변경할 수 없습니다.

정적 읽기 전용 : 정적 읽기 전용 유형 변수의 값은 런타임에 할당하거나 컴파일 타임에 할당하고 런타임에 변경할 수 있습니다. 그러나이 변수의 값은 정적 생성자에서만 변경할 수 있습니다. 그리고 더 이상 변경할 수 없습니다. 런타임에 한 번만 변경할 수 있습니다

참조 : c-sharpcorner


6

정적 읽기 전용 필드는 이후 버전에서 변경 될 수있는 값을 다른 어셈블리에 노출 할 때 유리합니다.

예를 들어, 어셈블리 X가 다음과 같이 상수를 노출 한다고 가정 합니다.

public const decimal ProgramVersion = 2.3;

어셈블리 가이 상수를 Y참조 X하고 사용하는 Y경우 컴파일 할 때 값 2.3이 어셈블리로 구워집니다 . 이는 X나중에 상수를 2.4로 설정하여 다시 컴파일하면 다시 컴파일 Y될 때까지 이전 값 2.3을 계속 사용 한다는 의미입니다 Y. 정적 읽기 전용 필드는이 문제를 방지합니다.

이를 보는 또 다른 방법은 미래에 변경 될 수있는 모든 값이 정의에 따라 일정하지 않으므로 하나의 값으로 표시해서는 안된다는 것입니다.


3

const :

  1. 신고시 가치를 부여해야합니다
  2. 컴파일 시간 상수

읽기 전용 :

  1. 선언시 또는 생성자를 사용하여 런타임 중에 값을 제공 할 수 있습니다. 값은 사용 된 생성자에 따라 다를 수 있습니다.
  2. 런타임 상수

3

Const : const 변수 값은 선언과 함께 정의해야하며 그 후에는 변경되지 않습니다. const는 암시 적으로 정적이므로 클래스 인스턴스를 만들지 않고도 액세스 할 수 있습니다. 컴파일 타임에 값이 있습니다.

ReadOnly : 선언 할 때와 런타임에 생성자를 사용하여 정의 할 수있는 읽기 전용 변수 값입니다. 읽기 전용 변수는 클래스 인스턴스가 없으면 액세스 할 수 없습니다.

정적 읽기 전용 : 정적 읽기 전용 변수 값 정적 생성자뿐만 아니라 다른 생성자는 사용하지 않고 선언하면서 정의 할 수 있습니다.이 변수는 클래스 인스턴스 (정적 변수)를 만들지 않고도 액세스 할 수 있습니다.

다른 어셈블리의 변수를 사용해야하는 경우 정적 읽기 전용이 더 좋습니다. 아래 링크에서 자세한 내용을 확인하십시오.

https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/


왜 당신이 대답을 downvote 했습니까 말해 주실 수 있습니까, 그래서 나는 여기뿐만 아니라 나 자신을 업데이트 할 수 있습니다.
user1756922

DV는 아니지만이 답변이 이미 포괄적 인 답변에 아무것도 추가하지 않을 수도 있습니다.
Marc L.

그들은 주위에 복사 된 이후 실제로, 자바 우리는 여러 사람이 (서로 참조) 상호 운용 클래스 파일과 다른 단지를 생산하는 프로젝트에 있던 후반 90 년대에 다시 공공 CONST 문자열이 문제를 버전 있었다의 기억
조지 Birbilis

2

C # .Net의 const와 정적 읽기 전용 필드에는 약간의 차이가 있습니다.

const는 컴파일 타임에 값으로 초기화해야합니다.

const는 기본적으로 정적이며 상수 값으로 초기화해야하며 나중에 수정할 수 없습니다. 모든 데이터 유형에 사용할 수는 없습니다. 예를 들어, DateTime. DateTime 데이터 유형과 함께 사용할 수 없습니다.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public static readonly string Name = string.Empty; //No error, legal

읽기 전용은 정적으로 선언 될 수 있지만 필수는 아닙니다. 선언 할 때 초기화 할 필요가 없습니다. 생성자를 사용하여 값을 한 번 할당하거나 변경할 수 있습니다. 따라서 읽기 전용 필드의 값을 한 번 변경할 수 있습니다 (정적이든 아니든 중요하지 않음). const로는 불가능합니다.


0

상수는 이름에서 알 수 있듯이 필드는 변경되지 않으며 일반적으로 코드에서 컴파일 타임에 정적으로 정의됩니다.

읽기 전용 변수는 특정 조건에서 변경할 수있는 필드입니다.

상수처럼 처음 선언 할 때 초기화 될 수 있지만 일반적으로 생성자 내에서 객체를 생성하는 동안 초기화됩니다.

위에서 언급 한 조건에서 초기화가 수행 된 후에는 변경할 수 없습니다.

정적 읽기 전용은 정적이 아니며 결코 변경되지 않는 경우 나에게 선택의 여지가없는 것처럼 들립니다. 따라서 공용 const를 사용하십시오. 변경 할 수 있다면 상수가 아니며 필요에 따라 읽기를 사용할 수 있습니다 -또는 단지 일반 변수.

또한 또 다른 중요한 차이점은 상수는 클래스에 속하고 읽기 전용 변수는 인스턴스에 속한다는 것입니다!


0

const (컴파일 타임에 결정)는 switch 문이나 속성 생성자와 같이 읽기 전용 정적을 사용할 수없는 경우에 사용할 수 있습니다. 읽기 전용 필드는 런타임시에만 확인되고 일부 코드 구성에는 컴파일 시간 보증이 필요하기 때문입니다. 생성자에서 읽기 전용 정적을 계산할 수 있는데, 이는 필수적이고 유용한 것입니다. 내 의견으로는 사용법이 다르기 때문에 차이점은 기능적입니다.

메모리 할당의 관점에서, 최소한 문자열 (참조 유형)은 둘 다 인터 닝되고 하나의 인터 닝 된 인스턴스를 참조한다는 점에서 차이가없는 것 같습니다.

개인적으로 내 기본값은 읽기 전용 정적이며, 특히 컴파일 타임에 대부분의 값이 필요하지 않기 때문에 의미적이고 논리적으로 이해가됩니다. 그리고 공공 읽기 전용 정적은 표시된 답변 상태와 같이 특이하거나 드문 일이 아닙니다 System.String.Empty. 예를 들어 하나입니다.


0

const정적 읽기 전용 선언의 또 다른 차이점은 메모리 할당에 있습니다.

정적 필드는 해당 유형 의 인스턴스가 아닌 객체 의 유형 에 속합니다 . 결과적으로 클래스가 처음으로 참조되면 정적 필드는 나머지 시간 동안 메모리에 "라이브"되고 정적 필드의 동일한 인스턴스는 모든 유형의 인스턴스에서 참조됩니다.

반면에 const 필드는 유형의 인스턴스에 속합니다.

할당 해제 메모리가 더 중요하다면 const 를 사용하는 것이 좋습니다 . 속도 인 경우 정적 읽기 전용 을 사용하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.