답변:
참조가 전달됩니다. 그러나 기술적 으로 참조로 전달 되지는 않습니다 . 이것은 미묘하지만 매우 중요한 차이입니다. 다음 코드를 고려하십시오.
void DoSomething(string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomething(strMain);
Console.WriteLine(strMain); // What gets printed?
}
여기서 일어나는 일을 이해하기 위해 알아야 할 세 가지가 있습니다.
strMain
전달되지 않습니다. 그것은 A의 참조 형, 하지만 기준 자체입니다 값에 의해 전달 . 매개 변수를 ref
계산 하지 않고 키워드 없이 매개 변수를 전달할 때마다 out
값으로 무언가를 전달한 것입니다.그래서 그것은 당신이 가치로 참조를 전달하고 있다는 것을 의미합니다. 참조 유형이므로 참조 만 스택에 복사되었습니다. 그러나 그것은 무엇을 의미합니까?
C # 변수는 참조 유형 또는 값 유형 입니다. C # 매개 변수는 참조로 전달 되거나 전달 value로 전달됩니다 . 여기서 용어는 문제입니다. 이것들은 똑같이 들리지만 그렇지 않습니다.
ANY 유형의 매개 변수를 전달하고 ref
키워드를 사용하지 않으면 값으로 전달한 것입니다. 가치로 전달했다면 실제로 전달한 것은 사본이었습니다. 그러나 매개 변수가 참조 유형이면 복사 한 것은 참조가 아닌 참조 입니다.
다음은 Main
메서드 의 첫 번째 줄입니다 .
string strMain = "main";
우리는이 줄에 두 가지를 만들었습니다 : 값이 main
어딘가에 메모리에 저장되어 있는 문자열과 strMain
그것을 가리키는 참조 변수 입니다.
DoSomething(strMain);
이제 해당 참조를 DoSomething
. 우리는 그것을 가치로 전달했기 때문에 우리가 복사본을 만들었다는 것을 의미합니다. 참조 유형이므로 문자열 자체가 아니라 참조를 복사했음을 의미합니다. 이제 각각 메모리에서 동일한 값을 가리키는 두 개의 참조가 있습니다.
DoSomething
방법 의 상단은 다음과 같습니다 .
void DoSomething(string strLocal)
어떤 ref
키워드, 그래서 strLocal
와 strMain
같은 값을 가리키는 두 개의 서로 다른 언급은 없다. 재 할당하면 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
는 참조를 스택에 복사하지 않고 전달했기 때문에 의 문자열이 실제로 변경됩니다.
따라서 문자열이 참조 유형이더라도 값으로 전달하면 호출 수신자에서 진행되는 모든 작업이 호출자의 문자열에 영향을주지 않습니다. 그러나 그것들 은 참조 유형 이기 때문에 전달하고자 할 때 전체 문자열을 메모리에 복사 할 필요가 없습니다.
ref
키워드가 필요하다는 것 입니다. 참조로 전달하면 차이가 있음을 증명하려면 다음 데모를 참조하십시오. rextester.com/WKBG5978
ref
키워드에 유틸리티가 있다는 것을 알고 있습니다 . C #에서 값으로 참조 유형을 전달하는 것이 참조로 전달하고 참조 유형을 전달하는 "전통적인"(예 : C) 개념처럼 보이는 이유를 설명하려고했습니다. 참조로 C #에서 참조에 대한 참조를 값으로 전달하는 것과 비슷합니다.
Foo(string bar)
으로 생각 될 수있는 Foo(char* bar)
반면 Foo(ref string bar)
될 것이다 Foo(char** bar)
(또는 Foo(char*& bar)
또는 Foo(string& bar)
C ++에서). 물론, 그것은 당신이 그것을 매일 어떻게 생각해야 하는가는 아니지만 실제로는 내부에서 일어나는 일을 마침내 이해하는 데 도움이되었습니다.
C #의 문자열은 변경할 수없는 참조 개체입니다. 이것은 그들에 대한 참조가 (값으로) 전달되고 문자열이 생성되면 수정할 수 없음을 의미합니다. 수정 된 버전의 문자열 (하위 문자열, 잘린 버전 등)을 생성하는 메서드 는 원래 문자열의 수정 된 복사본 을 만듭니다 .
문자열은 특별한 경우입니다. 각 인스턴스는 변경할 수 없습니다. 문자열의 값을 변경하면 메모리에 새 문자열이 할당됩니다.
따라서 참조 만 함수에 전달되지만 문자열이 편집되면 새 인스턴스가되고 이전 인스턴스를 수정하지 않습니다.
Uri
(클래스)와 Guid
(구조체)도 특별한 경우입니다. System.String
클래스 또는 구조체 기원의 다른 불변 유형보다 "값 유형"처럼 작동 하는 방식을 알지 못합니다 .
Uri
& 와 달리 특별한 생성 의미가 Guid
있습니다. 문자열 변수에 문자열 리터럴 값을 할당 할 수 있습니다. 문자열 int
은 재 할당되는 것처럼 변경 가능한 것처럼 보이지만 암시 적으로 객체를 생성합니다 ( new
키워드 없음) .