[C#] 객체를 전달할 때 왜 ‘ref’키워드를 사용합니까?

객체를 메소드에 전달하는 경우 왜 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을 호출 한 후 toriginal를 참조하는 것이 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};foofoo.Lengthfoo.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에서 그렇게하면 디자인 문제가 있다고 생각합니다!