[.net] .NET에서 문자열은 어떻게 전달됩니까?

string함수에 a 를 전달할 때 문자열의 내용에 대한 포인터가 전달 struct됩니까? 아니면 전체 문자열이 a와 같이 스택의 함수에 전달 됩니까?



답변

참조가 전달됩니다. 그러나 기술적 으로 참조로 전달 되지는 않습니다 . 이것은 미묘하지만 매우 중요한 차이입니다. 다음 코드를 고려하십시오.

void DoSomething(string strLocal)
{
    strLocal = "local";
}
void Main()
{
    string strMain = "main";
    DoSomething(strMain);
    Console.WriteLine(strMain); // What gets printed?
}

여기서 일어나는 일을 이해하기 위해 알아야 할 세 가지가 있습니다.

  1. 문자열은 C #의 참조 유형입니다.
  2. 그들은 또한 불변이므로 문자열을 변경하는 것처럼 보이는 작업을 할 때마다 그렇지 않습니다. 완전히 새로운 문자열이 생성되고 참조가 해당 문자열을 가리키며 이전 문자열이 버려집니다.
  3. 문자열은 참조 유형이지만 참조로 strMain전달되지 않습니다. 그것은 A의 참조 형, 하지만 기준 자체입니다 값에 의해 전달 . 매개 변수를 ref계산 하지 않고 키워드 없이 매개 변수를 전달할 때마다 out값으로 무언가를 전달한 것입니다.

그래서 그것은 당신이 가치로 참조를 전달하고 있다는 것을 의미합니다. 참조 유형이므로 참조 만 스택에 복사되었습니다. 그러나 그것은 무엇을 의미합니까?

값으로 참조 유형 전달 : 이미 수행 중입니다.

C # 변수는 참조 유형 또는 값 유형 입니다. C # 매개 변수는 참조로 전달 되거나 전달 value로 전달됩니다 . 여기서 용어는 문제입니다. 이것들은 똑같이 들리지만 그렇지 않습니다.

ANY 유형의 매개 변수를 전달하고 ref키워드를 사용하지 않으면 값으로 전달한 것입니다. 가치로 전달했다면 실제로 전달한 것은 사본이었습니다. 그러나 매개 변수가 참조 유형이면 복사 한 것은 참조가 아닌 참조 입니다.

다음은 Main메서드 의 첫 번째 줄입니다 .

string strMain = "main";

우리는이 줄에 두 가지를 만들었습니다 : 값이 main어딘가에 메모리에 저장되어 있는 문자열과 strMain그것을 가리키는 참조 변수 입니다.

DoSomething(strMain);

이제 해당 참조를 DoSomething. 우리는 그것을 가치로 전달했기 때문에 우리가 복사본을 만들었다는 것을 의미합니다. 참조 유형이므로 문자열 자체가 아니라 참조를 복사했음을 의미합니다. 이제 각각 메모리에서 동일한 값을 가리키는 두 개의 참조가 있습니다.

수신자 내부

DoSomething방법 의 상단은 다음과 같습니다 .

void DoSomething(string strLocal)

어떤 ref키워드, 그래서 strLocalstrMain같은 값을 가리키는 두 개의 서로 다른 언급은 없다. 재 할당하면 strLocal

strLocal = "local";   

… 저장된 값을 변경하지 않았습니다. 우리는라는 참조를 가져 와서 strLocal새로운 문자열을 겨냥했습니다. 무슨 일이 일어나는 strMain우리가 그렇게 할 때? 아무것도. 여전히 이전 문자열을 가리키고 있습니다.

string strMain = "main";    // Store a string, create a reference to it
DoSomething(strMain);       // Reference gets copied, copy gets re-pointed
Console.WriteLine(strMain); // The original string is still "main" 

불변성

잠시 시나리오를 변경해 보겠습니다. 우리가 문자열로 작업하지 않고 생성 한 클래스와 같은 변경 가능한 참조 유형을 사용한다고 상상해보십시오.

class MutableThing
{
    public int ChangeMe { get; set; }
}

당신은 경우 에 따라 기준 objLocal이, 당신은 그것의 속성을 변경할 수 있습니다 가리키는 객체를 :

void DoSomething(MutableThing objLocal)
{
     objLocal.ChangeMe = 0;
} 

MutableThing메모리 에는 여전히 하나만 있고 복사 된 참조와 원래 참조가 여전히 참조를 가리 킵니다. 자체 속성 MutableThing이 변경되었습니다 .

void Main()
{
    var objMain = new MutableThing();
    objMain.ChangeMe = 5;
    Console.WriteLine(objMain.ChangeMe); // it's 5 on objMain

    DoSomething(objMain);                // now it's 0 on objLocal
    Console.WriteLine(objMain.ChangeMe); // it's also 0 on objMain   
}

아,하지만 문자열은 불변입니다! ChangeMe설정할 속성 이 없습니다 . strLocal[3] = 'H'C 스타일 char배열 에서 할 수있는 것처럼 C #에서는 할 수 없습니다 . 대신 완전히 새로운 문자열을 구성해야합니다. 변화에 대한 유일한 방법은 strLocal다른 문자열에 대한 참조를 가리 키도록하고, 수단 아무것도 것을 당신은 위해 할 strLocal에 영향을 줄 수 있습니다 strMain. 값은 변경할 수 없으며 참조는 사본입니다.

참조로 참조 전달

차이점이 있음을 증명하기 위해 참조로 참조를 전달하면 다음과 같은 결과가 발생합니다.

void DoSomethingByReference(ref string strLocal)
{
    strLocal = "local";
}
void Main()
{
    string strMain = "main";
    DoSomethingByReference(ref strMain);
    Console.WriteLine(strMain);          // Prints "local"
}

이번에 Main는 참조를 스택에 복사하지 않고 전달했기 때문에 의 문자열이 실제로 변경됩니다.

따라서 문자열이 참조 유형이더라도 값으로 전달하면 호출 수신자에서 진행되는 모든 작업이 호출자의 문자열에 영향을주지 않습니다. 그러나 그것들 참조 유형 이기 때문에 전달하고자 할 때 전체 문자열을 메모리에 복사 할 필요가 없습니다.

추가 리소스 :


답변

C #의 문자열은 변경할 수없는 참조 개체입니다. 이것은 그들에 대한 참조가 (값으로) 전달되고 문자열이 생성되면 수정할 수 없음을 의미합니다. 수정 된 버전의 문자열 (하위 문자열, 잘린 버전 등)을 생성하는 메서드 는 원래 문자열의 수정 된 복사본 을 만듭니다 .


답변

문자열은 특별한 경우입니다. 각 인스턴스는 변경할 수 없습니다. 문자열의 값을 변경하면 메모리에 새 문자열이 할당됩니다.

따라서 참조 만 함수에 전달되지만 문자열이 편집되면 새 인스턴스가되고 이전 인스턴스를 수정하지 않습니다.


답변