.NET String을 변경할 수없는 이유는 무엇입니까? [복제]
이 질문에는 이미 답변이 있습니다.
우리 모두 알다시피, String 은 불변입니다. String이 변경 불가능하고 StringBuilder 클래스가 변경 가능한 이유는 무엇입니까 ?
- 변경 불가능한 유형의 인스턴스는 본질적으로 스레드로부터 안전합니다. 스레드를 수정할 수 없으므로 스레드가 다른 스레드를 방해하는 방식으로 스레드를 수정하는 위험이 제거됩니다 (참조 자체는 다른 문제임).
- 유사하게, 앨리어싱이 변경을 생성 할 수 없다는 사실 (x와 y가 모두 같은 객체를 참조하면 x에 대한 변경이 y에 대한 변경을 수반하는 경우)은 상당한 컴파일러 최적화를 허용합니다.
- 메모리 절약 최적화도 가능합니다. 우리는 같은 원리의 다른 버전을 할 수 있지만, 인턴과 원자화가 가장 명백한 예입니다. 불변의 객체를 비교하고 참조를 복제본으로 교체하여 모두 동일한 인스턴스를 가리 키도록 (시간이 많이 걸리지 만 엄청난 양의 메모리를 절약하기위한 1 분의 추가 시작) 문제의 경우 성능이 승리합니다). 수행 할 수없는 변경 가능한 객체
- 불변 타입을 메소드로
out
또는 매개 변수에 전달하지 않으면 부작용이 발생ref
하지 않습니다 (객체가 아닌 참조가 변경되므로). 따라서 프로그래머string x = "abc"
는 분석법 시작시 분석법 본문에서 변경되지 않는 경우 분석법x == "abc"
끝에서 변경 사항을 알고 있습니다 . - 개념적으로 의미론은 가치 유형과 비슷합니다. 특히 평등은 정체성보다는 국가에 근거한다. 이것은 의미합니다
"abc" == "ab" + "c"
. 불변성을 요구하지는 않지만, 그러한 문자열에 대한 참조가 수명 내내 항상 "abc"와 동일하다는 사실 (불변성을 필요로 함)은 이전 값과의 동등성을 유지하는 것이 중요하고 정확성을 보장하기 훨씬 쉬운 키로 사용합니다. (문자열은 실제로 키로 일반적으로 사용됩니다). - 개념적으로, 불변 인 것이 더 합리적 일 수 있습니다. 크리스마스에 한 달을 더해도 크리스마스는 바뀌지 않았으며 1 월 말에 새로운 날짜가 생겼습니다. 따라서 변경 가능한 것을 변경하는 것보다
Christmas.AddMonths(1)
새로운 것을 만드는 것이 합리적DateTime
입니다. (예를 들어, 변경 가능한 객체로 내 이름을 변경하면 변경된 이름은 "Jon"이 변경되지 않고 다른 Jons는 영향을받지 않습니다. - 복제는 빠르고 간단하며 복제본을 만들 수 있습니다
return this
. 어쨌든 사본을 변경할 수 없기 때문에 자신의 사본을 안전한 것으로 가장하는 것이 안전합니다. - [편집, 나는 이것을 잊었다]. 내부 상태는 객체간에 안전하게 공유 할 수 있습니다. 예를 들어, 배열, 시작 색인 및 개수로 지원되는 목록을 구현하는 경우 하위 범위를 만드는 데 가장 비싼 부분은 객체를 복사하는 것입니다. 불변이었다 경우, 그 하위 범위 객체는 시작 인덱스와 동일한 배열을 참조와 함께 변화를 갖는 셀 수 매우 건설 시간에 상당한 변화.
대체로 목적의 일부로 변경되지 않은 객체의 경우 변경 불가능한 장점이 많이 있습니다. 주요 단점은 추가 구성이 필요하다는 것인데, 여기에서도 종종 과장되어 있습니다 (StringBuilder가 기본 구성으로 동등한 일련의 연결보다 효율적이되기 전에 몇 가지 추가 작업을 수행해야 함을 기억하십시오).
가변성이 객체의 목적의 일부 (연봉이 절대 변하지 않는 Employee 객체에 의해 모델링되기를 원함)의 일부인 경우 단점이 될 수 있지만 때로는 많은 웹 및 기타 비 상태에서 유용 할 수 있습니다 응용 프로그램, 읽기 작업을 수행하는 코드는 업데이트를 수행하는 코드와 별개이며 다른 객체를 사용하는 것이 자연 스러울 수 있습니다. 객체를 변경할 수 없게 만든 다음 해당 패턴을 강제로 적용하지만 패턴이 이미 있으면 "읽기"객체를 만들 수 있습니다 성능 및 정확성 보증 이득에 대해서는 불변).
기록 중 복사는 중간 단계입니다. 여기서 "실제"클래스는 "상태"클래스에 대한 참조를 보유합니다. 상태 클래스는 복사 작업에서 공유되지만 상태를 변경하면 상태 클래스의 새 복사본이 생성됩니다. 이것은 C #보다 C ++에서 더 자주 사용되므로 std : string이 변경 불가능한 유형을 유지하면서 불변 유형의 장점 중 일부를 즐기지는 않습니다.
문자열을 불변으로 만드는 것은 많은 장점이 있습니다. 자동 스레드 안전을 제공하고 문자열을 단순하고 효과적인 방식으로 내장 유형처럼 동작시킵니다. 또한 런타임시 추가 효율성 (예 : 효과적인 문자열 인터 닝을 통한 리소스 사용량 감소)을 허용하며 타사 API 호출로 문자열을 변경할 수 없기 때문에 보안상의 이점이 있습니다.
불변 문자열의 한 가지 주요 단점을 해결하기 위해 StringBuilder가 추가되었습니다. 불변 유형의 런타임 구성은 많은 GC 압력을 유발하며 본질적으로 느립니다. 이를 처리하기 위해 명시적이고 변경 가능한 클래스를 만들면 문자열 클래스에 불필요한 복잡성을 추가하지 않고도이 문제가 해결됩니다.
문자열은 실제로 변경할 수 없습니다. 그들은 단지 공개적으로 불변입니다. 공개 인터페이스에서 수정할 수 없음을 의미합니다. 그러나 내부는 실제로 변경 가능합니다.
내가 믿지 않는다면 reflectorString.Concat
사용 하여 정의를 보십시오 . 마지막 줄은 ...
int length = str0.Length;
string dest = FastAllocateString(length + str1.Length);
FillStringChecked(dest, 0, str0);
FillStringChecked(dest, length, str1);
return dest;
보시다시피 FastAllocateString
반환 값은 비어 있지만 할당 된 문자열을 반환합니다.FillStringChecked
실제로 FastAllocateString
는 extern 메소드이고 FillStringChecked
안전하지 않으므로 포인터를 사용하여 바이트를 복사합니다.
아마도 더 좋은 예가 있지만 이것이 지금까지 찾은 것입니다.
문자열 관리는 비용이 많이 드는 프로세스입니다. 문자열을 불변으로 유지하면 반복되는 문자열을 다시 만들지 않고 재사용 할 수 있습니다.
문자열은 참조 유형이므로 복사되지 않지만 참조로 전달됩니다. 이것을 값으로 전달되는 C ++ std :: string 객체 (변경 불가능하지 않음)와 비교하십시오. 즉, Hashtable에서 String을 키로 사용하려면 C ++에서 괜찮습니다 .C ++은 문자열을 복사하여 나중에 비교를 위해 해시 테이블 (실제로는 std :: hash_map이지만 여전히)에 키를 저장하기 때문입니다. . 따라서 나중에 std :: string 인스턴스를 수정하더라도 괜찮습니다. 그러나 .Net에서는 Hashtable에서 String을 사용하면 해당 인스턴스에 대한 참조가 저장됩니다. 이제 문자열을 변경할 수 없다고 가정하고 무슨 일이 일어나는지보십시오. 1. 누군가 "hello"키를 가진 x 값을 Hashtable에 삽입합니다. 2. Hashtable은 문자열의 해시 값을 계산하고 문자열과 값 x에 대한 참조를 적절한 버킷에 배치합니다. 삼. 사용자는 String 인스턴스를 "bye"로 수정합니다. 4. 이제 누군가 "hello"와 관련된 해시 테이블의 값을 원합니다. 올바른 버킷을 찾게되지만 문자열을 비교할 때 "bye"! = "hello"라고 표시되므로 값이 반환되지 않습니다. 5. 누군가 "bye"값을 원할까요? "bye"는 아마도 다른 해시를 가지고 있으므로 해시 테이블은 다른 버킷에서 볼 수 있습니다. 해당 버킷에 "bye"키가 없으므로 여전히 항목을 찾을 수 없습니다. 아마도 다른 해시가있을 수 있으므로 해시 테이블은 다른 버킷으로 보입니다. 해당 버킷에 "bye"키가 없으므로 여전히 항목을 찾을 수 없습니다. 아마도 다른 해시가있을 수 있으므로 해시 테이블은 다른 버킷으로 보입니다. 해당 버킷에 "bye"키가 없으므로 여전히 항목을 찾을 수 없습니다.
Making strings immutable means that step 3 is impossible. If somebody modifies the string he's creating a new string object, leaving the old one alone. Which means the key in the hashtable is still "hello", and thus still correct.
So, probably among other things, immutable strings are a way to enable strings that are passed by reference to be used as keys in a hashtable or similar dictionary object.
You never have to defensively copy immutable data. Despite the fact that you need to copy it to mutate it, often the ability to freely alias and never have to worry about unintended consequences of this aliasing can lead to better performance because of the lack of defensive copying.
Just to throw this in, an often forgotten view is of security, picture this scenario if strings were mutable:
string dir = "C:\SomePlainFolder";
//Kick off another thread
GetDirectoryContents(dir);
void GetDirectoryContents(string directory)
{
if(HasAccess(directory) {
//Here the other thread changed the string to "C:\AllYourPasswords\"
return Contents(directory);
}
return null;
}
You see how it could be very, very bad if you were allowed to mutate strings once they were passed.
Strings are passed as reference types in .NET.
Reference types place a pointer on the stack, to the actual instance that resides on the managed heap. This is different to Value types, who hold their entire instance on the stack.
When a value type is passed as a parameter, the runtime creates a copy of the value on the stack and passes that value into a method. This is why integers must be passed with a 'ref' keyword to return an updated value.
When a reference type is passed, the runtime creates a copy of the pointer on the stack. That copied pointer still points to the original instance of the reference type.
The string type has an overloaded = operator which creates a copy of itself, instead of a copy of the pointer - making it behave more like a value type. However, if only the pointer was copied, a second string operation could accidently overwrite the value of a private member of another class causing some pretty nasty results.
As other posts have mentioned, the StringBuilder class allows for the creation of strings without the GC overhead.
Strings and other concrete objects are typically expressed as immutable objects to improve readability and runtime efficiency. Security is another, a process can't change your string and inject code into the string
Imagine you pass a mutable string to a function but don't expect it to be changed. Then what if the function changes that string? In C++, for instance, you could simply do call-by-value (difference between std::string
and std::string&
parameter), but in C# it's all about references so if you passed mutable strings around every function could change it and trigger unexpected side effects.
This is just one of various reasons. Performance is another one (interned strings, for example).
There are five common ways by which a class data store data that cannot be modified outside the storing class' control:
- As value-type primitives
- By holding a freely-shareable reference to class object whose properties of interest are all immutable
- By holding a reference to a mutable class object that will never be exposed to anything that might mutate any properties of interest
- As a struct, whether "mutable" or "immutable", all of whose fields are of types #1-#4 (not #5).
- By holding the only extant copy of a reference to an object whose properties can only be mutated via that reference.
Because strings are of variable length, they cannot be value-type primitives, nor can their character data be stored in a struct. Among the remaining choices, the only one which wouldn't require that strings' character data be stored in some kind of immutable object would be #5. While it would be possible to design a framework around option #5, that choice would require that any code which wanted a copy of a string that couldn't be changed outside its control would have to make a private copy for itself. While it hardly be impossible to do that, the amount of extra code required to do that, and the amount of extra run-time processing necessary to make defensive copies of everything, would far outweigh the slight benefits that could come from having string
be mutable, especially given that there is a mutable string type (System.Text.StringBuilder
) which accomplishes 99% of what could be accomplished with a mutable string
.
Immutable Strings also prevent concurrency-related issues.
Imagine being an OS working with a string that some other thread was modifying behind your back. How could you validate anything without making a copy?
참고URL : https://stackoverflow.com/questions/2365272/why-net-string-is-immutable
'Programing' 카테고리의 다른 글
Pyplot으로 모든 서브 플로트 위에 하나의 메인 타이틀을 설정하는 방법은 무엇입니까? (0) | 2020.05.20 |
---|---|
Prim과 반대로 Kruskal을 언제 사용해야합니까? (0) | 2020.05.20 |
플러그인에 대해 npm에서 피어 종속성을 사용하는 이유는 무엇입니까? (0) | 2020.05.20 |
유니온으로 주문하는 방법 (0) | 2020.05.20 |
양식없이 문자열 배열을 ASP.NET MVC 컨트롤러에 게시하려면 어떻게해야합니까? (0) | 2020.05.20 |