String.Empty가 상수가 아닌 이유는 무엇입니까?


188

.Net에서 왜 String.Empty가 상수 대신 읽기 전용입니까? 그 결정의 근거가 무엇인지 아는 사람이 있는지 궁금합니다.


5
질문은 문제를 해결할 수 있습니다. 간단한 대답은 아무도 모릅니다 ...
gdoron이 Monica를 지원

네, Eric Lippert의 답변은 +1입니다. 감사합니다!
트래비스

특히 Decimal.Zero는 (사용자 관점에서 볼 때 ...)
Hamish Grubijan

답변:


148

그 이유 static readonly대신에 사용됩니다 const여기에 마이크로 소프트에 의해 지시 된 바와 같이, 관리되지 않는 코드를 사용하기 때문이다 공유 소스 공용 언어 인프라 2.0 릴리스 . 살펴볼 파일은 sscli20\clr\src\bcl\system\string.cs입니다.

Empty 상수는 빈 문자열 값을 보유합니다. 컴파일러가 이것을 리터럴로 표시하지 않도록 String 생성자를 호출해야합니다.

이것을 리터럴로 표시하면 네이티브에서 액세스 할 수있는 필드로 표시되지 않습니다.

CodeProject의이 편리한 기사 에서이 정보를 찾았습니다 .


(존 소총이 ... 할 수 없기 때문에) 여기에서 볼이 댓글을 설명 할 수 있다면 정말 감사하겠습니다 : stackoverflow.com/questions/8462697/...
gdoron 모니카 지원하고있다

2
@ gdoron : 내 추측 (그리고 추측)은 이것입니다. 값이 리터럴 (상수)로 정의되면 값이 참조되는 위치에 값이 삽입되는 반면 리터럴로 정의되지 않은 경우 값의 소스가 참조되고 실제 값은 런타임에 검색됩니다. 후자는 런타임에 네이티브와 .NET 사이에서 문자열의 적절한 마샬링이 발생할 수 있다고 확신합니다. 리터럴 인 경우 네이티브 컴파일러는 리터럴 값을 네이티브 코드로 가져와야합니다. 아마도 그렇지 않습니다. 실현 가능 한. 그러나 이것은 모두 내 추측입니다.
Jeff Yates

7
메서드의 기본 매개 변수 값으로 string.Empty 대신 ""를 사용해야 함을 의미합니다. 약간 성가신입니다.
nicodemus13.

17
""는 실수처럼 보일 수 있습니다. 빈은 고의적 인 의도를 보여줍니다
Christopher Stevenson

3
@JeffYates 나는 그것이 일관성이 없다는 사실이 이미 성가신 것이라고 덧붙이고 싶습니다. 사람들은 코드의 나머지 부분을보고 "왜 String.Empty 대신" "를 사용합니까?" 나는 String.Empty그 이유 때문에 더 이상 사용 하지 않는 것을 진지하게 고려 하고 있습니다.
julealgon

24

나는 여기에 많은 혼란과 나쁜 반응이 있다고 생각합니다.

우선, const필드는 static멤버입니다 ( 인스턴스 멤버가 아님) 아님)입니다.

섹션 10.4 C # 언어 사양의 상수를 확인하십시오.

상수는 정적 멤버로 간주되지만 상수 선언은 정적 수정자를 요구하거나 허용하지 않습니다.

만약 public const 회원은 정적, 하나는 상수는 새 개체를 만들 것이라고 생각하지 못했습니다.

이를 감안할 때 다음 코드 줄은 새 객체 생성과 관련하여 정확히 동일한 기능을 수행 합니다 .

public static readonly string Empty = "";
public const string Empty = "";

다음은 2의 차이점을 설명하는 Microsoft의 참고 사항입니다.

읽기 전용 키워드는 const 키워드와 다릅니다. const 필드는 필드 선언시에만 초기화 할 수 있습니다. 읽기 전용 필드는 선언 또는 생성자에서 초기화 될 수 있습니다. 따라서 읽기 전용 필드는 사용 된 생성자에 따라 다른 값을 가질 수 있습니다. 또한 const 필드는 컴파일 타임 상수이지만 읽기 전용 필드는 런타임 상수에 사용할 수 있습니다 ...

그래서 여기서 유일하게 그럴듯한 대답은 Jeff Yates의 것입니다.


const 및 정적 읽기 전용의 C # 사양에 관한 친절한 단어와 설명을 보려면 +1하십시오.
Jeff Yates 님이

17
이를 다시 읽고, 그 동의 const stringstatic readonly string같은 일을한다. 상수 값은 링크 된 코드로 대체되는 반면 정적 읽기 전용 값은 참조됩니다. 당신이있는 경우 const라이브러리 B에 의해 사용되는 라이브러리 A의를 라이브러리 B는 모든 참조 대체 할 const의 리터럴 값과 변수를; 해당 변수가 static readonly대신 참조 된 경우 해당 변수가 참조되고 런타임에 값이 결정됩니다.
Jeff Yates

3
라이브러리를 참조 할 때 Jeff의 요점이 중요합니다. B를 다시 컴파일하지 않고 A를 재 컴파일하고 재배포해도 B는 여전히 이전 값을 사용합니다.
Mark Sowul

5
String.Empty read only instead of a constant?

문자열을 일정하게 만들면 컴파일러는 실제로 문자열로 바뀝니다. 호출하는 모든 곳 바뀌고 코드를 같은 문자열로 채우고 코드가 실행될 때 다른 메모리에서 해당 문자열을 반복해서 읽어야합니다. 데이터.

문자열을 한곳에서만 읽은 채 그대로두면 String.Empty 프로그램은 같은 문자열을 한곳에 만 유지하고 읽거나 참조하여 데이터를 메모리에 최소로 유지합니다.

또한 String.Empty를 const로 사용하여 dll을 컴파일하고 어떤 이유로 String.Empty가 변경되면 컴파일 된 dll은 더 이상 동일하게 작동하지 않습니다. cost . 내부 코드에서 실제로 문자열의 사본을 유지하기 때문입니다. 모든 전화에.

예를 들어이 코드를 참조하십시오

public class OneName
{
    const string cConst = "constant string";
    static string cStatic = "static string";
    readonly string cReadOnly = "read only string";

    protected void Fun()
    {
        string cAddThemAll ;

        cAddThemAll = cConst;
        cAddThemAll = cStatic ;
        cAddThemAll = cReadOnly;    
    }
}

컴파일러는 다음과 같이 올 것이다 :

public class OneName
{
    // note that the const exist also here !
    private const string cConst = "constant string";
    private readonly string cReadOnly;
    private static string cStatic;

    static OneName()
    {
        cStatic = "static string";
    }

    public OneName()
    {
        this.cReadOnly = "read only string";
    }

    protected void Fun()
    {
        string cAddThemAll ;

        // look here, will replace the const string everywhere is finds it.
        cAddThemAll = "constant string";
        cAddThemAll = cStatic;
        // but the read only will only get it from "one place".
        cAddThemAll = this.cReadOnly;

    }
}

그리고 어셈블리 호출

        cAddThemAll = cConst;
0000003e  mov         eax,dword ptr ds:[09379C0Ch] 
00000044  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cStatic ;
00000047  mov         eax,dword ptr ds:[094E8C44h] 
0000004c  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cReadOnly;
0000004f  mov         eax,dword ptr [ebp-3Ch] 
00000052  mov         eax,dword ptr [eax+0000017Ch] 
00000058  mov         dword ptr [ebp-44h],eax 

편집 : 오타 수정


따라서 이것은 const 문자열이 항상 그 const를 포함하는 클래스로 인스턴스화되어야한다는 것을 의미합니까? 정적 읽기 전용을 사용하는 것이 훨씬 낫습니다.
berserker

@theberserker는 더 좋지만 사용할 수있는 모든 옵션이 있습니다.
Aristos

> 컴파일 된 dll은 더 이상 동일하게 작동하지 않습니다. 비용 때문에 내부 코드가 실제로 모든 호출에서 문자열의 사본을 유지하기 때문입니다. @Aristos 그것은 옳지 않습니다. 코드가 컴파일되면 문자열의 "복사"가 실행 파일의 TEXT 블록에서 참조되고 모든 코드는 동일한 메모리 블록을 참조합니다. 두 번째 단계에서 인용 한 것은 단순히 중간 단계입니다.
Peter Dolkens

@ user1533523 감사합니다-이 점을 확인하기 위해 시간을 내면 테스트하겠습니다.
Aristos

어셈블리 코드는 어떻게 얻었습니까? C #은 어셈블리로 컴파일되지 않습니다!
jv110

0

이 답변은 역사적 목적으로 존재합니다.

원래:

때문에 String클래스 상수가 될 수 없습니다.

확장 된 토론 :

이 답변을 심사하는 데 유용한 대화가 많이 생겼으며, 삭제하는 대신이 내용이 직접 재생산됩니다.

.NET에서 (Java와 달리) string과 String은 정확히 동일합니다. 그리고 네, .NET에서 문자열 리터럴 상수를 가질 수 있습니다 – DrJokepu Feb 3 '09 at 16:57

당신은 클래스가 상수를 가질 수 없다고 말하는가? – StingyJack 2009 년 2 월 3 일 16:58

예, 개체는 읽기 전용을 사용해야합니다. 구조체 만 상수를 수행 할 수 있습니다. 나는 당신이 string대신 사용할 때 생각String컴파일러 하면 const가 읽기 전용으로 변경됩니다. C 프로그래머를 행복하게하는 것과 관련된 모든 것. – Garry Shutler 2009 년 2 월 3 일 16:59

tvanfosson은 조금 더 장황하게 설명했습니다. "Y를 포함하는 클래스이기 때문에 X는 상수가 될 수 없습니다"는 문맥이 너무 조금도 없었습니다.) – Leonidas

string.Empty는 String 클래스 자체가 아니라 String 클래스의 인스턴스, 즉 빈 문자열을 반환하는 정적 속성입니다. – tvanfosson 2009 년 2 월 3 일 17:01

Empty는 String 클래스의 읽기 전용 인스턴스입니다 (속성이 아님). – senfo 2 월 3 '09 일 17:02

머리가 아프다. 나는 아직도 내가 옳다고 생각하지만 지금은 확실하지 않다. 오늘 밤 연구가 필요했습니다! – Garry Shutler 2009 년 2 월 3 일 17:07

빈 문자열은 문자열 클래스의 인스턴스입니다. Empty는 String 클래스의 정적 필드입니다 (속성이 아님, 정정되었습니다). 기본적으로 포인터와 그것이 가리키는 것의 차이점. 읽기 전용이 아닌 경우 Empty 필드가 참조하는 인스턴스를 변경할 수 있습니다. – tvanfosson 2009 년 2 월 3 일 17:07

개리, 당신은 어떤 연구를 할 필요가 없습니다. 생각 해봐 문자열은 클래스입니다. Empty는 String의 인스턴스입니다. – senfo 2 월 3 '09 일 17:12

내가 얻지 못한 것이 있습니다 : 어떻게 지구상에서 String 클래스의 정적 생성자가 String 클래스의 인스턴스를 만들 수 있습니까? 일종의 "닭고기 또는 계란"시나리오가 아닌가? – DrJokepu 2012 년 2 월 3 일 17:12 5

이 대답은 System.String 이외의 거의 모든 클래스에 맞습니다. .NET은 문자열에 대해 많은 특수 성능을 수행하며 그중 하나는 문자열 상수를 가질 수 있다는 것입니다. 이 경우 Jeff Yates가 정답입니다. – Joel Mueller 2009 년 2 월 3 일 19:25

§7.18에서 설명한 것처럼 상수 표현식은 컴파일 타임에 완전히 평가할 수있는 표현식입니다. 문자열 이외의 참조 유형의 널이 아닌 값을 작성하는 유일한 방법은 새 연산자를 적용하는 것이며, 새 연산자는 상수 표현식에서 허용되지 않으므로 참조 유형의 상수에 가능한 유일한 값 문자열 이외의 null이 있습니다. 앞의 두 의견은 C # 언어 사양에서 직접 가져와 Joel Mueller가 언급 한 내용을 반복합니다. – senfo 2 월 4'09시 15:05 5


정답에 투표하십시오. 정의로 이동하면 String 클래스에 있고 String 인스턴스라는 것을 알 수 있습니다. 소문자로 표시되는 사실은 컴파일러 마술입니다.
Garry Shutler

당신을 downvoted 한 사람은 아니지만 .NET에서 (Java와는 달리) string과 String은 정확히 동일합니다. 그리고 네, 당신은 .NET에서 상수 리터럴 문자열을 가질 수 있습니다
타마스 Czinege

10
이 답변은 System.String 이외의 거의 모든 클래스에 맞습니다. .NET은 문자열에 대한 많은 특수 성능을 수행하며 그중 하나는 문자열 상수를 가질 수 있다는 것입니다. 이 경우 Jeff Yates가 정답입니다.
Joel Mueller

7
훨씬 나은 답변이 나왔을 때이 답변을 거의 삭제했지만이 의견에 대한 토론은 가치가 있습니다.
Garry Shutler

1
@Garry, 당신은 내가 당신의 마지막 코멘트를 읽은 것을 운이 좋다. 그렇지 않으면 나는 또한 downvote 할 것이다. 문자열은 .NET에 특별한 기능이 있습니다. 이벤트 클래스는 const 클래스 일 수 있습니다.
Shimmy Weitzhandler가
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.