C #에서 참조 유형 변수에 "ref"를 사용하는 것은 무엇입니까?


176

키워드가 없는 매개 변수로 값 유형 ( int, struct등)을 ref전달하면 해당 변수의 사본이 메소드에 전달되지만 ref키워드를 사용하면 해당 변수에 대한 참조가 전달됩니다. 새로운 것이 아닙니다.

그러나 ref키워드가 없어도 클래스와 같은 참조 유형을 사용 하면 사본이 아닌 메소드에 참조가 전달됩니다. 그렇다면 ref키워드를 참조 유형과 함께 사용하는 것은 무엇 입니까?


예를 들어 보자.

var x = new Foo();

다음의 차이점은 무엇입니까?

void Bar(Foo y) {
    y.Name = "2";
}

void Bar(ref Foo y) {
    y.Name = "2";
}

답변:


154

foo사용 하는 포인트를 변경할 수 있습니다 y.

Foo foo = new Foo("1");

void Bar(ref Foo y)
{
    y = new Foo("2");
}

Bar(ref foo);
// foo.Name == "2"

17
기본적으로 원래 참조에 대한 참조를 얻습니다
lhahne

2
원래 참조 '참조'를 변경할 수 있습니다.
user7116 2016 년

1
크리스, 당신의 설명은 훌륭합니다. 이 개념을 이해하도록 도와 주셔서 감사합니다.
Andreas Grech 2016 년

4
따라서 객체에서 'ref'를 사용하는 것은 C ++에서 이중 포인터를 사용하는 것과 같습니다.
Tom Hazel

1
@TomHazel : -ish는 , 당신은 무엇 포인터 포인트로 변경 C에서 "더블"포인터를 ++ 사용하고 제공했다.
user7116

29

실제 참조 를 수정하려는 경우가 있지만 대상이 아닌 오브젝트는 다음과 같습니다.

void Swap<T>(ref T x, ref T y) {
    T t = x;
    x = y;
    y = t;
}

var test = new[] { "0", "1" };
Swap(ref test[0], ref test[1]);

21

Jon Skeet은 C #에서 매개 변수 전달에 대한 훌륭한 기사를 썼습니다 . 값, 참조 ( ref) 및 출력 ( out) 별로 매개 변수 전달의 정확한 동작 및 사용법을 명확하게 설명합니다 .

다음은 ref매개 변수 와 관련하여 해당 페이지에서 중요한 인용문입니다 .

참조 매개 변수는 함수 멤버 호출에 사용 된 변수의 값을 전달하지 않습니다. 변수 자체를 사용합니다. 함수 멤버 선언에서 변수의 새 스토리지 위치를 작성하는 대신 동일한 스토리지 위치가 사용되므로 함수 멤버의 변수 값과 참조 매개 변수의 값은 항상 동일합니다. 참조 매개 변수에는 선언과 호출의 일부로 ref 수정자가 필요합니다. 즉 참조로 무언가를 전달할 때 항상 명확합니다.


11
내가 생각하기 때문에 값에 의해 참조를 전달하는 친구에게 당신의 개 가죽 끈을 통과 비유처럼 나는 ... 그것은,하지만 빠르게 분해 당신 친구가 트레이드 업 경우로 Shitzu을 도베르만에 그가 당신을 넘겨 전에 아마 통지 가죽 끈 ;-)
corlettk

16

여기에 아주 잘 설명되어 있습니다 : http://msdn.microsoft.com/en-us/library/s6938f28.aspx

기사에서 요약 :

참조 유형의 변수는 데이터를 직접 포함하지 않습니다. 데이터에 대한 참조를 포함합니다. 참조 유형 매개 변수를 값으로 전달하면 클래스 구성원의 값과 같이 참조가 가리키는 데이터를 변경할 수 있습니다. 그러나 참조 자체의 값을 변경할 수는 없습니다. 즉, 동일한 참조를 사용하여 새 클래스에 메모리를 할당하고 블록 외부에 유지시킬 수 없습니다. 그렇게하려면 ref 또는 out 키워드를 사용하여 매개 변수를 전달하십시오.


4
설명은 실제로 매우 좋습니다. 그러나 링크 전용 답변은 SO에 권장되지 않습니다. 나는 독자들에게 편의를 위해 기사의 요약을 추가했습니다.
Marcel

10

ref 키워드로 참조 유형을 전달하면 참조로 참조를 전달하며 호출하는 메소드는 매개 변수에 새 값을 지정할 수 있습니다. 이 변경 사항은 호출 범위로 전파됩니다. ref가 없으면 참조가 값으로 전달되며 이러한 일이 발생하지 않습니다.

C #에는 ref와 비슷한 'out'키워드가 있습니다. 단, 'ref'를 사용하면 메소드를 호출하기 전에 인수를 초기화해야하며 'out'을 사용하면 수신 메소드에 값을 지정해야합니다.


5

전달 된 참조를 수정할 수 있습니다. 예 :

void Bar()
{
    var y = new Foo();
    Baz(ref y);
}

void Baz(ref Foo y)
{
    y.Name = "2";

    // Overwrite the reference
    y = new Foo();
}

당신은 또한 사용할 수 있습니다 밖으로 참조가 전달에 대해 상관하지 않는 경우 :

void Bar()
{
    var y = new Foo();
    Baz(out y);
}

void Baz(out Foo y)
{
    // Return a new reference
    y = new Foo();
}

4

또 다른 코드

class O
{
    public int prop = 0;
}

class Program
{
    static void Main(string[] args)
    {
        O o1 = new O();
        o1.prop = 1;

        O o2 = new O();
        o2.prop = 2;

        o1modifier(o1);
        o2modifier(ref o2);

        Console.WriteLine("1 : " + o1.prop.ToString());
        Console.WriteLine("2 : " + o2.prop.ToString());
        Console.ReadLine();
    }

    static void o1modifier(O o)
    {
        o = new O();
        o.prop = 3;
    }

    static void o2modifier(ref O o)
    {
        o = new O();
        o.prop = 4;
    }
}

3

기존 답변 외에도

당신이이 방법의 차이에 대한 질문과 같이 사용에는 공동 (NTRA) 차이가 없습니다 ref또는 out:

class Foo { }
class FooBar : Foo { }

static void Bar(Foo foo) { }
static void Bar(ref Foo foo) { foo = new Foo(); }

void Main()
{
    Foo foo = null;
    Bar(foo);           // OK
    Bar(ref foo);       // OK

    FooBar fooBar = null;
    Bar(fooBar);        // OK (covariance)
    Bar(ref fooBar);    // compile time error
}

1

메소드의 매개 변수는 항상 사본을 전달하는 것 같습니다. 질문은 무엇의 사본입니다. 복사는 객체의 복사 생성자에 의해 수행되며 모든 변수는 C #의 Object이기 때문에 모든 경우에 해당됩니다. 변수 (객체)는 일부 주소에 사는 사람들과 같습니다. 우리는 그 주소에 사는 사람들을 바꾸거나 전화 번호부에서 그 주소에 사는 사람들에 대해 더 많은 참고 문헌을 만들 수 있습니다 (얕은 사본 만들기). 따라서 둘 이상의 식별자가 동일한 주소를 참조 할 수 있습니다. 참조 유형은 더 많은 공간을 원하므로 화살표로 스택의 식별자에 직접 연결된 값 유형과 달리 힙에 다른 주소 (더 큰 공간)가 있습니다. 이 공간은 힙에서 가져와야합니다.

값 유형 : 식별자 (값 = 스택 값의 주소 포함) ----> 값 유형의 값

참조 유형 : 식별자 (값 = 스택 값의 주소 포함) ----> (값 = 힙 값의 주소 포함) ----> 힙 값 (대부분 다른 값의 주소가 포함됨) 배열 [0], 배열 [1], 배열 [2] 방향

값을 변경하는 유일한 방법은 화살표를 따르는 것입니다. 하나의 화살표가 값에 도달 할 수없는 방식으로 손실 / 변경되는 경우.


-1

참조 변수는 한 장소에서 다른 장소로 주소를 전달하므로 어느 곳에서든지 업데이트하면 모든 장소에 반영되므로 REF의 용도는 무엇입니까? 참조 변수 (405)는 새로운 메모리가 메소드에 전달 된 참조 변수에 할당되지 않을 때까지 유효합니다.

새로운 메모리가 할당되면 (410),이 객체 (408)의 값 변경은 어디에도 반영되지 않을 것이다. 이 심판을 위해 온다. Ref는 참조를 참조하므로 새 메모리가 할당 될 때마다 해당 위치를 가리 키므로 알 수 있으므로 everyOne이 값을 공유 할 수 있습니다. 더 선명하게 이미지를 볼 수 있습니다.

참조 변수의 참조

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.