객체를 메소드에 전달하는 경우 왜 ref 키워드를 사용해야합니까? 어쨌든 이것이 기본 동작이 아닙니까?
예를 들면 다음과 같습니다.
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t.Something = "Bar";
}
}
public class TestRef
{
public string Something { get; set; }
}
출력은 “Bar”입니다. 이는 객체가 참조로 전달되었음을 의미합니다.
답변
ref
객체가 무엇인지 변경하려면 a를 전달 하십시오.
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);
void DoSomething(ref TestRef t)
{
t = new TestRef();
t.Something = "Not just a changed t, but a completely different TestRef object";
}
DoSomething을 호출 한 후 t
original를 참조하는 것이 new TestRef
아니라 완전히 다른 객체를 나타냅니다.
변경할 수없는 객체의 값을 변경하려는 경우에도 유용합니다 (예 : a) string
. string
일단 작성된 값은 변경할 수 없습니다 . 그러나를 사용하면 ref
값이 다른 다른 문자열을 변경하는 함수를 만들 수 있습니다.
편집 : 다른 사람들이 언급했듯이. ref
필요한 경우가 아니면 사용 하지 않는 것이 좋습니다 . 를 사용 ref
하면 메소드가 다른 것에 대한 인수를 자유롭게 변경할 수 있으므로 메소드 호출자는 이러한 가능성을 처리하도록 코딩해야합니다.
또한 매개 변수 유형이 객체 인 경우 객체 변수는 항상 객체에 대한 참조로 작동합니다. 이는 ref
키워드가 사용될 때 참조에 대한 참조를 얻었음을 의미합니다 . 이를 통해 위에 제공된 예에 설명 된대로 작업을 수행 할 수 있습니다. 그러나 매개 변수 유형이 기본 값 (예 🙂 인 int
경우이 매개 변수가 메소드 내에 지정되면 전달 된 인수의 값은 메소드가 리턴 한 후에 변경됩니다.
int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10
void Change(ref int x)
{
x = 5;
}
void WillNotChange(int x)
{
x = 10;
}
답변
“값으로 참조 전달”과 “참조로 매개 변수 / 인수 전달”을 구별해야합니다.
나는 뉴스 그룹에 올 때마다주의 깊게 글을 쓰지 않기 위해 주제에 대해 상당히 긴 기사 를 작성했습니다. 🙂
답변
.NET에서 매개 변수를 메소드에 전달하면 사본이 작성됩니다. 값 형식에서 값을 수정하면 메서드 범위에 있고 메서드를 종료하면 손실됩니다.
참조 유형을 전달할 때 사본도 작성되지만 참조의 사본입니다. 즉, 동일한 오브젝트에 대한 메모리에 두 개의 참조가 있습니다. 따라서 참조를 사용하여 객체를 수정하면 수정됩니다. 그러나 참조 자체를 수정하면 참조가 사본임을 기억해야합니다. 그러면 메소드를 종료 할 때 모든 변경 사항도 손실됩니다.
사람들이 이전에 언급했듯이 과제는 참조의 수정이므로 손실됩니다.
public void Method1(object obj) {
obj = new Object();
}
public void Method2(object obj) {
obj = _privateObject;
}
위의 방법은 원본 객체를 수정하지 않습니다.
예제의 약간의 수정
using System;
class Program
{
static void Main(string[] args)
{
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(t);
Console.WriteLine(t.Something);
}
static public void DoSomething(TestRef t)
{
t = new TestRef();
t.Something = "Bar";
}
}
public class TestRef
{
private string s;
public string Something
{
get {return s;}
set { s = value; }
}
}
답변
TestRef는 클래스 (참조 객체)이기 때문에 참조로 전달하지 않고 t 내부의 내용을 변경할 수 있습니다. 그러나 t를 참조로 전달하면 TestRef가 원래 t가 참조하는 것을 변경할 수 있습니다. 즉, 다른 객체를 가리 키도록합니다.
답변
ref
당신 과 함께 쓸 수 있습니다 :
static public void DoSomething(ref TestRef t)
{
t = new TestRef();
}
그리고 방법이 완료되면 t가 변경됩니다.
답변
foo
참조 유형 (예 :)의 변수 (예 :)를 “개체 # 24601″형식의 객체 식별자 를 List<T>
보유하는 것으로 생각하십시오 . 명령문 이 “개체 # 24601″(4 개의 항목이있는 목록)을 보유 한다고 가정하십시오 . 그런 다음 호출 하면 객체 # 24601에 길이가 표시되고 4가 응답하므로 4가됩니다.foo = new List<int> {1,5,7,9};
foo
foo.Length
foo.Length
경우 foo
사용하지 않고 메서드에 전달되어 ref
, 그 방법은 # 24601을 Object로 변경할 수 있습니다. 이러한 변경의 결과로 foo.Length
더 이상 4와 같지 않을 수 있습니다. 그러나 메소드 자체는 변경할 수 없으며 foo
“Object # 24601″을 계속 보유합니다.
매개 변수 foo
로 전달 ref
하면 호출 된 메서드가 개체 # 24601뿐만 아니라 foo
자체 도 변경할 수 있습니다. 이 메소드는 새 객체 # 8675309를 생성하고에 대한 참조를에 저장할 수 있습니다 foo
. 그렇게 foo
하면 더 이상 “개체 # 24601″이 아니라 “개체 # 8675309″가됩니다.
실제로, 참조 형 변수는 “Object # 8675309″형식의 문자열을 보유하지 않습니다. 그들은 의미있게 숫자로 변환 될 수있는 것도 가지고 있지 않습니다. 각 참조 유형 변수는 약간의 비트 패턴을 보유하지만 이러한 변수에 저장된 비트 패턴과 이들이 식별하는 객체 사이에는 고정 된 관계가 없습니다. 코드가 객체 또는 객체에 대한 참조에서 정보를 추출 할 수있는 방법은 없으며 나중에 코드가 원래 객체를 식별하는 참조를 보유하거나 알지 않는 한 다른 참조가 동일한 객체를 식별했는지 여부를 결정합니다.
답변
이것은 C에서 포인터로 포인터를 전달하는 것과 같습니다. .NET에서는 원래 T가 참조하는 것을 개인적 으로 변경할 수 있습니다. 으로 .NET에서 그렇게하면 디자인 문제가 있다고 생각합니다!