767

함수로 수정할 수 있도록 개체를 전달해야하는 함수를 만들고 있습니다. 차이점은 무엇입니까?

public void myFunction(ref MyClass someClass)

public void myFunction(out MyClass someClass)

어떤 것을 사용해야하며 그 이유는 무엇입니까?


  • 당신:내가 수정할 수 있도록 개체를 전달해야합니다.그것은 닮았다.MyClass~ 될 것입니다.class타입, 즉 참조 타입이다. 이 경우 전달하는 객체는myFunction아무리해도ref/out예어.myFunction~을받을 것이다.새로운참조를 가리키는 참조같은객체로 만들 수 있으며 원하는만큼 객체를 수정할 수 있습니다. 차이점은ref키워드를 사용하면myFunction받은같은동일한 객체에 대한 참조. 그것은 중요한 경우에만myFunction포인트를 가리키는 참조를 변경했다.다른목적. - Jeppe Stig Nielsen
  • @ AnthonyKolesov가 아주 완벽 할 때 혼란스러운 답변으로 혼란스러워합니다. - o0'.
  • 메서드를 선언하면 메서드에서 여러 값을 반환 할 때 유용합니다. 하나의 인수는 널 (null)로 지정할 수 있습니다. 이것에 의해, 메소드는 값을 임의로 돌려 줄 수가 있습니다. - Yevgraf Andreyevich Zhivago
  • 여기에 더 이해할 수있는 예와 함께 설명되어 있습니다 :)dotnet-tricks.com/Tutorial/csharp/… - Prageeth godage
  • @ JeppeStigNielsen의 논평은 기술적으로 OP의 실제 질문에 대한 (유일한) 정답입니다. 메서드에 객체를 전달하여메서드는 객체를 수정할 수 있습니다., 단순히 (참조) 객체를 값으로 메소드에 전달하십시오. 오브젝트 인수를 통해 메소드 내에서 오브젝트 변경원래의 객체를 수정한다.(동일한 객체를 참조하는) 별도의 변수가 포함되어 있어도 마찬가지입니다. - David R Tribble

24 답변


1022

ref함수에 들어가기 전에 객체가 초기화되었다는 것을 컴파일러에 알려주는 반면,out객체가 함수 내부에서 초기화된다는 것을 컴파일러에 알립니다.

그러면서ref양방향입니다.outout-only입니다.


  • 밖으로 특이한 또 다른 멋진 점은 함수가 out 매개 변수에 지정해야한다는 것입니다. 할당되지 않은 상태로 둘 수는 없습니다. - Daniel Earwicker
  • &ref; #39; 값 유형에만 적용 할 수 있습니까? 참조 유형은 항상 ref로 전달되므로 - faulty
  • 예. 구조체를 포함한 값 유형 - Rune Grimstad
  • @faulty : 아니요, ref는 값 유형에만 적용 할 수있는 것이 아닙니다. ref / out은 C / C ++의 포인터와 비슷하지만 직접 객체 대신 (C #에서 간접적으로) 객체의 메모리 위치를 처리합니다. - thr
  • @faulty : 직관적으로, ref 형식을 사용하지 않는 한 참조 형식은 항상 C #에서 값으로 전달됩니다. myval = somenewval을 설정하면 해당 기능 범위에서만 효과가 나타납니다. ref 키워드를 사용하면 myval이 somenewval을 가리 키도록 변경할 수 있습니다. - JasonTrue

447

그만큼ref수정자는 다음을 의미합니다.

  1. 값이 이미 설정되어 있습니다.
  2. 메서드는 그것을 읽고 수정할 수 있습니다.

그만큼out수정자는 다음을 의미합니다.

  1. 값이 설정되지 않았으므로 메소드에서 읽을 수 없습니다....까지그것은 설정됩니다.
  2. 방법절대로 필요한 것돌아 오기 전에 설정하십시오.


  • 이 대답은 ref 키워드와 달리 out 키워드를 사용할 때 컴파일러가 부과하는 제한 사항을 가장 명확하고 간결하게 설명합니다. - Dr. Wily's Apprentice
  • MSDN에서 : ref 매개 변수는 사용 전에 초기화되어야하며 out 매개 변수는 전달되기 전에 명시 적으로 초기화 할 필요가 없으며 이전 값은 무시됩니다. - Shiva Kumar
  • out메서드가 호출되기 전에 초기화 된 경우 해당 메서드에서 설정하기 전에 메서드 내에서 전혀 읽을 수 있습니까? 호출 된 메서드가 호출하는 메서드가 인수로 전달한 것을 읽을 수 있습니까? - Panzercrisis
  • Panzercrisis, "out"에 대해, 호출 된 메소드는 그것이 이미 설정되어 있으면 읽을 수있다. 하지만 다시 설정해야합니다. - robert jebakumar2

135

Dom이 TPS 보고서에 대한 메모에 대해 Peter의 방에 나타났습니다.

돔이 논쟁의 여지가 있다면 그는 메모 사본을 인쇄 할 것입니다.

돔이 논쟁 거리가된다면, 그는 피터에게 그가 가지고 갈 수있는 새로운 메모 사본을 인쇄하게 할 것입니다.


  • 심판이 연필로 보고서를 작성했기 때문에 베드로는 그것을 수정할 수있었습니다. - Deebster
  • 당신이 아는 데버스터, 그 은유는 당신에게 아무 것도하지 않았어요. 왜 그렇게 고문해야합니까? ;) - Michael Blackburn
  • 재미 있지만 아직 교육, stackoverflow이 같은 더 많은 게시물이 필요합니다 - Frank Visaggio
  • 누군가가이 답변을 반 재미 없다고 생각하는 경우 영화 '사무실 공간'을 시청하시기 바랍니다. - displayName
  • Dom과 Peters의 상사는 Dom을지지 할 것이고, Peter와 Peter가 손을 뗄 때까지 새로운 것을 인쇄 할 것을 강요한다. - Patrick Artner

48

나는 설명에서 내 손을 시험 할 것이다 :

가치 유형이 올바르게 작동하는 방식을 이해하고 있다고 생각합니다. 값 유형은 (int, long, struct 등)입니다. ref 명령을 사용하지 않고 함수를 전송하면데이터. 함수에서 해당 데이터에 대해 수행하는 작업은 원본이 아닌 복사본에만 적용됩니다. ref 명령은 ACTUAL 데이터를 보내고 변경 사항은 함수 외부의 데이터에 영향을 미칩니다.

좋아, 참조 형식에 대한 혼란스러운 부분은 다음과 같습니다.

참조 유형을 만들 수 있습니다.

List<string> someobject = new List<string>()

새로 시작할 때일부 대상두 부분이 생성됩니다.

  1. 데이터를 저장하는 메모리 블록일부 대상.
  2. 해당 블록에 대한 참조 (포인터) 데이터의.

이제 네가 보낼 때.일부 대상그것을 참조하지 않고 메서드에 복사합니다.참고포인터가 아니라 데이터. 그래서 당신은 지금 이것을 가지고 있습니다 :

(outside method) reference1 => someobject
(inside method)  reference2 => someobject

동일한 객체를 가리키는 두 개의 참조입니다. 에 대한 속성을 수정하면일부 대상reference2를 사용하면 reference1이 가리키는 동일한 데이터에 영향을줍니다.

 (inside method)  reference2.Add("SomeString");
 (outside method) reference1[0] == "SomeString"   //this is true

reference2를 null로 설정하거나 새 데이터를 가리키면 reference1에는 영향을 미치지 않으며 reference1에는 데이터가 가리 킵니다.

(inside method) reference2 = new List<string>();
(outside method) reference1 != null; reference1[0] == "SomeString" //this is true

The references are now pointing like this:
reference2 => new List<string>()
reference1 => someobject

이제 당신이 보낼 때 어떻게됩니까?일부 대상방법으로 심판에 의해? 그만큼실제 참조일부 대상메서드에 전송됩니다. 이제 데이터에 대한 참조가 하나만 있습니다.

(outside method) reference1 => someobject;
(inside method)  reference1 => someobject;

그러나 이것은 무엇을 의미합니까? 그것은 정확하게 두 가지 주요 사항을 제외하고 ref로가 아니라 someobject를 보내는 것과 같습니다.

1) 메서드 내에서 참조를 null로 설정하면 메서드 외부의 참조가 null이됩니다.

 (inside method)  reference1 = null;
 (outside method) reference1 == null;  //true

2) 이제 완전히 다른 데이터 위치에 대한 참조를 가리킬 수 있으며 함수 외부의 참조는 이제 새 데이터 위치를 가리 킵니다.

 (inside method)  reference1 = new List<string>();
 (outside method) reference1.Count == 0; //this is true


  • 결국 (참고로) 데이터에 대한 참조는 하나 뿐이지 만 두 개의 별칭이 있음을 의미합니다. 권리? - Sadiq
  • 명확한 설명을 위해 upvoted. 하지만이 질문에 대한 대답은 아니라고 생각합니다. 차이점을 설명하지는 않습니다.refout매개 변수. - Joyce Babu
  • 놀랄 만한. 너는 다음과 같이 설명 할 수 있니?out예어? - Asif Mushtaq
  • 훌륭한 대답, cpp와 같은 ref 유형을 전달하는 방법을 이해하려고 시도했지만 ref 키워드를 사용하여 ref 유형을 전달하는 것이 이상한 것처럼 보였습니다. 그러나 이제는 실제로 그 사실을 합법적으로 할 수 있음을 알고 있습니다. - Phoera

27

심판이있다아웃.

너는 다음을 사용해야한다.out귀하의 요구 사항이 만족 스러울 때마다 선호합니다.


  • 방향성이없고 쓸모없는 가치관을 무시한다면 받아 들여지는 대답을 참조하십시오. - kenny
  • @kenny : 좀 더 명확하게 설명해 주실 수 있습니까? 즉, 답변의 정신을 유지하기 위해 어떤 단어를 변경하겠습니까?하지만 부정확성을 제거하십시오. 나의 대답은 초보자에게서 미친 추측이 아니다. 그러나 당신의 설명에 서두른 (terseness, typos) 그것이 있다고 생각되는 것처럼 보인다. 목표는 최소한의 단어로 차이점을 생각하는 방법을 제공하는 것입니다. - Ruben Bartelink
  • (값 유형, 참조 유형, 참조 전달, 값 전달, COM 및 C ++에 대해 잘 알고 있으면 설명에있는 개념을 참조하는 것이 유용하다는 것을 알아야합니다.) - Ruben Bartelink
  • 객체 참조는 값으로 전달됩니다 (" ref " 또는 " out " 키워드 사용시 제외). 개체를 ID 번호라고 생각하십시오. 클래스 변수가 " Object #1943 " 그 변수를 값으로 루틴에 전달하면 그 루틴은 Object #1943을 변경할 수 있지만 변수가 "Object #1943"이외의 다른 것으로 가리킬 수는 없습니다. 변수가 참조에 의해 전달 된 경우, 루틴은 변수 점이 "객체 #5441"을 유지하게 할 수있다. - supercat
  • @supercat : 저는 ref 대 val (그리고이 followup anaology)에 대한 당신의 설명을 좋아합니다. 내 생각에 케니는 실제로 그에게 설명 된 것이 필요하다고 생각하지 않는다. (상대적으로) 그의 코멘트가 혼란 스럽다. 그들은 단지 모든 사람들을 혼란스럽게하는 것처럼 우리가 모두이 고독한 코멘트를 제거 할 수 있었으면 좋겠다. 이 모든 넌센스의 근본 원인은 케니가 내 대답을 잘못 읽었고 추가 / 제거 / 교체되어야하는 한 단어를 아직 지적하지 않은 것 같습니다. 우리 셋 중 누구도 우리가 이미 알지 못했던 토론에서 어떤 것도 배웠지 만 다른 대답은 우스꽝스런 수의 상향 회의가 있습니다. - Ruben Bartelink

15

아웃:

C #에서는 메서드가 하나의 값만 반환 할 수 있습니다. 둘 이상의 값을 반환하려는 경우 out 키워드를 사용할 수 있습니다. 아웃 수정자는 리턴 참조별로 리턴합니다. 가장 간단한 대답은 메서드에서 값을 가져 오는 데 "out"이라는 키워드가 사용된다는 것입니다.

  1. 호출 함수에서 값을 초기화 할 필요는 없습니다.
  2. 호출 된 함수에 값을 지정해야합니다. 그렇지 않으면 컴파일러에서 오류를보고합니다.

심판 :

C #에서는 int, float, double 등과 같은 값 형식을 메서드 매개 변수의 인수로 전달하면 값에 의해 전달됩니다. 따라서 매개 변수 값을 수정하면 메서드 호출의 인수에 영향을 미치지 않습니다. 그러나 "ref"키워드로 매개 변수를 표시하면 실제 변수에 반영됩니다.

  1. 함수를 호출하기 전에 변수를 초기화해야합니다.
  2. 메소드의 ref 매개 변수에 값을 지정하는 것은 필수 사항이 아닙니다. 값을 변경하지 않으면 "ref"로 표시 할 필요가 있습니까?


  • "C #에서는 메서드가 하나의 값만 반환 할 수 있습니다. 둘 이상의 값을 반환하려는 경우 out 키워드를 사용할 수 있습니다. " " ref " 반환 값. 메소드에서 여러 값을 반환하려면 ref 및 out을 모두 사용할 수 있습니까? - Ned
  • C #7에서는 ValueTuples을 사용하여 여러 값을 반환 할 수 있습니다. - Iman Bahrampour

12

Dog Extending, Cat 예제. ref를 사용하는 두 번째 메소드는 호출자가 참조하는 객체를 변경합니다. 그러므로 "고양이"!!!

    public static void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog". 
        Bar(ref myObject);
        Console.WriteLine(myObject.Name); // Writes "Cat". 
    }

    public static void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

    public static void Bar(ref MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }


8

참조 유형 (클래스)을 전달하기 때문에 사용할 필요가 없습니다.ref왜냐하면 기본적으로참고실제 개체에 전달되므로 항상 참조 뒤에 개체를 변경합니다.

예:

public void Foo()
{
    MyClass myObject = new MyClass();
    myObject.Name = "Dog";
    Bar(myObject);
    Console.WriteLine(myObject.Name); // Writes "Cat".
}

public void Bar(MyClass someObject)
{
    someObject.Name = "Cat";
}

수업을 들으면 오랫동안 사용할 필요가 없습니다.ref메서드 내에서 개체를 변경하려는 경우


  • 새 객체가 만들어지고 반환되지 않는 경우에만 작동합니다. 새 개체가 만들어지면 이전 개체에 대한 참조가 손실됩니다. - etsuba
  • 이것은 잘못되었습니다. 다음을 시도해보십시오 : addsomeObject = nullBar종료 실행. 코드가 잘 실행됩니다.Bar인스턴스에 대한 참조가 무효화되었습니다. 지금 변경BarBar(ref MyClass someObject)다시 실행하십시오.NullReferenceException때문에Foo인스턴스에 대한 참조가 무효화되었습니다. - Keith

7

refout뒤에 오는 다름을 제외하면 유사하게 행동하십시오.

  • ref변수는 사용 전에 초기화해야합니다.out할당없이 변수를 사용할 수있다.
  • out매개 변수는이를 사용하는 함수에 의해 할당되지 않은 값으로 처리되어야합니다. 그래서 우리는 초기화 된out매개 변수를 호출하지만 함수가 실행될 때 값이 손실됩니다.


6

"빵 굽는 사람"

이는 첫 번째 문자열 참조가 "Baker"를 가리 키도록 변경하기 때문입니다. ref 키워드 (=> 문자열 참조에 대한 참조)를 통해 전달 했으므로 참조를 변경할 수 있습니다. 두 번째 호출은 문자열에 대한 참조 복사본을 가져옵니다.

문자열은 처음에는 특별한 것으로 보입니다. 하지만 문자열은 참조 클래스 일 뿐이며 정의하면

string s = "Able";

그런 다음 s는 "Able"이라는 텍스트가 포함 된 문자열 클래스에 대한 참조입니다! 동일한 변수에 대한 다른 지정

s = "Baker";

원래 문자열을 변경하지 않고 새로운 인스턴스를 만들고 그 인스턴스를 가리키게합니다!

다음과 같은 간단한 코드 예제로 시도해 볼 수 있습니다.

string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);

너는 무엇을 기대 하느냐? s2가 원래 인스턴스를 가리키고있는 동안 s의 참조를 다른 인스턴스로 설정하기 때문에 얻을 수있는 것은 여전히 "에이블"입니다.

편집하다: string은 또한 변경할 수 없습니다. 즉 기존의 문자열 인스턴스를 수정하는 메서드 나 속성이 없습니다. (문서에서 하나를 찾으려고 할 수는 있지만 아무 것도하지 않습니다 .-)). 모든 문자열 조작 메소드는 새로운 문자열 인스턴스를 반환합니다! (그런 이유로 StringBuilder 클래스를 사용할 때 종종 더 나은 성능을 얻습니다)


  • 정확하게. " 참조 유형 (클래스)을 전달 했으므로 ref를 사용할 필요가 없습니다. "라고 말하기 란 사실이 아닙니다. - Paul Mitchell
  • 이론적으로 그는 이렇게 말할 권리가 있습니다. 왜냐하면 그는 "수정할 수 있도록" 문자열에는 사용할 수 없습니다. 그러나 불변의 객체 "ref" 및 "아웃" 참조 유형에도 매우 유용합니다! (.NET에는 많은 불변 클래스가 포함되어 있습니다!) - mmmmmmmm
  • 예, 그렇습니다. 대부분의 객체가 변경 가능하기 때문에 문자열과 같이 변경할 수없는 객체를 생각하지 않았습니다. - Albic
  • 글쎄요, 이것은 LQP에서 볼 수있는 당황스러운 답입니다. 이것이 원래의 질문이 Able과 Baker에게 수정본이 없다고 언급했기 때문에 다른 의견에 대한 길고 철저한 답변 인 것만 제외하고는 문제가 아닙니다. 포럼 인 것처럼 말입니다. 나는 그것이 정말로 언제 돌아 왔는지에 관해 정말로 분류하지 않고 있었다고 생각한다. - Nathan Tuggy

6

예 (나 같은)로 배우는 사람들은안토니 콜레 쇼프 (Anthony Kolesov).

요점을 설명하기 위해 ref, out 및 다른 몇 가지 예제를 만들었습니다. 차이점을 이해하기위한 모범 사례는 다루지 않고 있습니다.

https://gist.github.com/2upmedia/6d98a57b68d849ee7091


4

아웃:return 문은 함수에서 하나의 값만 반환하는 데 사용할 수 있습니다. 그러나 출력 매개 변수를 사용하면 함수에서 두 개의 값을 반환 할 수 있습니다. 출력 매개 변수는 참조 매개 변수와 비슷하지만 데이터가 아닌 메서드에서 데이터를 전송한다는 점만 다릅니다.

다음 예는 이것을 설명합니다.

using System;

namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void getValue(out int x )
      {
         int temp = 5;
         x = temp;
      }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;

         Console.WriteLine("Before method call, value of a : {0}", a);

         /* calling a function to get the value */
         n.getValue(out a);

         Console.WriteLine("After method call, value of a : {0}", a);
         Console.ReadLine();

      }
   }
}

심판 :참조 매개 변수는 변수의 메모리 위치에 대한 참조입니다. 참조로 매개 변수를 전달하면 값 매개 변수와 달리 이러한 매개 변수에 대해 새 저장 위치가 만들어지지 않습니다. 참조 매개 변수는 메소드에 제공되는 실제 매개 변수와 동일한 메모리 위치를 나타냅니다.

C #에서는 ref 키워드를 사용하여 참조 매개 변수를 선언합니다. 다음 예제에서는이를 보여줍니다.

using System;
namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void swap(ref int x, ref int y)
      {
         int temp;

         temp = x; /* save the value of x */
         x = y;   /* put y into x */
         y = temp; /* put temp into y */
       }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;
         int b = 200;

         Console.WriteLine("Before swap, value of a : {0}", a);
         Console.WriteLine("Before swap, value of b : {0}", b);

         /* calling a function to swap the values */
         n.swap(ref a, ref b);

         Console.WriteLine("After swap, value of a : {0}", a);
         Console.WriteLine("After swap, value of b : {0}", b);

         Console.ReadLine();

      }
   }
}


4

ref 및 out 작업은 참조로 전달하고 C ++ 에서처럼 포인터로 전달하는 것과 같습니다.

ref의 경우, 인수는 선언되고 초기화되어야합니다.

out의 경우, 인수는 선언되어야하지만 초기화 될 수도 있고 초기화되지 않을 수도 있습니다.

        double nbr = 6; // if not initialized we get error
        double dd = doit.square(ref nbr);

        double Half_nbr ; // fine as passed by out, but inside the calling  method you initialize it
        doit.math_routines(nbr, out Half_nbr);


  • 변수를 인라인으로 선언 할 수 있습니다.out double Half_nbr. - Sebastian Hofmann

4

심판ref 매개 변수의 값이 이미 설정되어 있으면이 메서드에서 값을 읽고 수정할 수 있음을 나타냅니다. ref 키워드를 사용하는 것은 호출자가 매개 변수의 값을 초기화 할 책임이 있다고 말하는 것과 같습니다.


아웃컴파일러에게 객체의 초기화가 이 함수는 out 매개 변수에 함수를 할당해야합니다. 할당되지 않은 상태로 둘 수는 없습니다.


3

제작 시간 :

(1) 호출 메소드를 만든다.Main()

(2) List 객체 (참조 유형 객체)를 생성하여 변수에 저장합니다myList.

public sealed class Program 
{
    public static Main() 
    {
        List<int> myList = new List<int>();

런타임 중 :

(3) 런타임은 #00에 스택에 메모리를 할당하고 주소를 저장할 수있을 정도로 넓습니다 (#00 =myList왜냐하면 변수 이름은 실제로 메모리 위치의 별칭이기 때문입니다.

(4) 런타임은 메모리 위치 #FF의 힙에리스트 객체를 생성합니다 (이 모든 주소는 예를 들어 sake입니다)

(5) 그런 다음 런타임은 #00에 객체의 시작 주소 #FF를 저장합니다 (또는 단어로 포인터에 List 객체의 참조를 저장합니다.myList)

제작 시간으로 돌아 가기 :

(6) 그런 다음 List 객체를 인수로 전달합니다myParamList호출 된 메소드에modifyMyList새 List 객체를 할당합니다.

List<int> myList = new List<int>();

List<int> newList = ModifyMyList(myList)

public List<int> ModifyMyList(List<int> myParamList){
     myParamList = new List<int>();
     return myParamList;
}

런타임 중 :

(7) 런타임은 호출 된 메소드의 호출 루틴을 시작하고 그 일부로 매개 변수의 유형을 점검합니다.

(8) 참조 유형을 찾으면 #04에서 스택에 메모리를 할당하여 매개 변수 변수의 별명을 지정합니다myParamList.

(9) 그런 다음 #FF 값을 저장합니다.

(10) 런타임은 메모리 위치 #004에서 힙에 목록 객체를 만들고이 값으로 #04의 #FF를 대체합니다 (또는 원래 List 객체를 참조 해제하고이 메소드에서 새 List 객체를 가리킴)

#00의 주소는 변경되지 않고 #FF에 대한 참조를 유지합니다 (또는 원본myList포인터가 방해받지 않는다).


그만큼심판키워드는 (8)과 (9)에 대한 런타임 코드 생성을 건너 뛰는 컴파일러 지시문으로, 메서드 매개 변수에 대한 힙 할당이 없음을 의미합니다. 원래 #00 포인터를 사용하여 #FF에있는 오브젝트를 조작합니다. 원래 포인터가 초기화되지 않은 경우 런타임은 변수가 초기화되지 않았기 때문에 진행할 수 없다는 불평을 중지합니다

그만큼아웃keyword는 (9)와 (10)을 약간 수정 한 ref와 거의 같은 컴파일러 지시문입니다. 컴파일러는 인수가 초기화되지 않았으며 (8), (4) 및 (5)를 계속 사용하여 힙에 객체를 만들고 인수 주소에 시작 주소를 저장합니다. 초기화되지 않은 오류가 발생하지 않으며 저장된 이전 참조가 손실됩니다.


1

그들은 거의 동일합니다. 유일한 차이점은 out 매개 변수로 전달하는 변수를 초기화 할 필요가 없으며 ref 매개 변수를 사용하는 메서드는이를 설정해야한다는 것입니다.

int x;    Foo(out x); // OK 
int y;    Foo(ref y); // Error

Ref 매개 변수는 수정할 수있는 데이터를위한 것이고, 매개 변수는 이미 반환 값을 무언가로 사용하고있는 함수 (예 : int.TryParse)에 대한 추가 출력 데이터입니다.


1

 public static void Main(string[] args)
    {
        //int a=10;
        //change(ref a);
        //Console.WriteLine(a);
        // Console.Read();

        int b;
        change2(out b);
        Console.WriteLine(b);
        Console.Read();
    }
    // static void change(ref int a)
    //{
    //    a = 20;
    //}

     static void change2(out int b)
     {
         b = 20;
     }

이 코드를 확인하면 완전한 차이를 설명 할 수 있습니다. "ref"를 사용할 때 u가 이미 int / string을 초기화한다는 것을 의미합니다.

그러나  "out"을 사용할 때 그것은 두 조건에서 작동 wheather 유 int / 문자열 또는 초기화하지 하지만 그 함수에서 int / string을 초기화해야합니다.


1

참고 : ref 키워드는 인수를 참조로 전달하는 데 사용됩니다. 즉, 메소드에서 해당 매개 변수의 값이 변경되면 호출 메소드에 반영됩니다. ref 키워드를 사용하여 전달 된 인수는 호출 된 메소드에 전달되기 전에 호출 메소드에서 초기화되어야합니다.

아웃: out 키워드는 또한 ref 키워드와 같은 인수를 전달하는데도 사용되지만 값을 할당하지 않고 인수를 전달할 수 있습니다. out 키워드를 사용하여 전달 된 인수는 호출 된 메소드로 초기화되기 전에 호출 된 메소드에서 초기화되어야합니다.

public class Example
{
 public static void Main() 
 {
 int val1 = 0; //must be initialized 
 int val2; //optional

 Example1(ref val1);
 Console.WriteLine(val1); 

 Example2(out val2);
 Console.WriteLine(val2); 
 }

 static void Example1(ref int value) 
 {
 value = 1;
 }
 static void Example2(out int value) 
 {
 value = 2; 
 }
}

/* Output     1     2     

메서드 오버로딩에서 참조 및 출력

ref와 out은 동시에 메서드 오버로딩에 사용할 수 없습니다. 그러나 ref 및 out은 런타임에 다르게 처리되지만 컴파일 타임에 동일하게 처리됩니다 (CLR은 ref 및 out을 위해 IL을 작성하는 동안 두 개를 구별하지 않습니다).


0

아래에서는 두 가지 모두를 사용한 예제를 보여 줬습니다.참조아웃. 자, 여러분 모두는 심판에 대해 밝혀 질 것입니다.

아래에 언급 된 예에서 내가 코멘트 할 때// myRefObj = new myClass {Name = "외부 참조 요청 !!"}};줄에 오류가 발생합니다."할당되지 않은 지역 변수 'myRefObj'사용", 그런 오류는 없습니다.아웃.

Ref 사용 위치: in 매개 변수를 사용하여 프로 시저를 호출 할 때 동일한 매개 변수가 해당 proc의 출력을 저장하는 데 사용됩니다.

사용 장소 :매개 변수가없는 프로 시저를 호출하면 동일한 매개 변수가 해당 프로 시저의 값을 반환하는 데 사용됩니다. 출력에주의하십시오.

public partial class refAndOutUse : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        myClass myRefObj;
        myRefObj = new myClass { Name = "ref outside called!!  <br/>" };
        myRefFunction(ref myRefObj);
        Response.Write(myRefObj.Name); //ref inside function

        myClass myOutObj;
        myOutFunction(out myOutObj);
        Response.Write(myOutObj.Name); //out inside function
    }

    void myRefFunction(ref myClass refObj)
    {
        refObj.Name = "ref inside function <br/>";
        Response.Write(refObj.Name); //ref inside function
    }
    void myOutFunction(out myClass outObj)
    {
        outObj = new myClass { Name = "out inside function <br/>" }; 
        Response.Write(outObj.Name); //out inside function
    }
}

public class myClass
{
    public string Name { get; set; }
} 


0

파라미터를 수신하는 방법의 관점에서,refoutC #은 모든 메소드가 모든 메소드에 쓰기를 요구한다는 것입니다.out매개 변수를 전달하기 전에 반환해야하며, 매개 변수로 전달하는 것 이외의 다른 매개 변수를 사용해서는 안됩니다.out매개 변수로 전달하거나 매개 변수로 전달할 때까지out매개 변수를 다른 방법으로 보내거나 직접 작성하십시오. 일부 다른 언어는 이러한 요구 사항을 부과하지 않습니다. C #에서 선언 된 가상 또는 인터페이스 메소드.out매개 변수는 이러한 매개 변수에 특별한 제한을 두지 않는 다른 언어로 겹쳐 쓸 수 있습니다.

호출자의 관점에서 볼 때 C #은 많은 경우에out매개 변수는 전달 된 변수가 먼저 읽히지 않고 기록되게합니다. 이 가정은 다른 언어로 작성된 메소드를 호출 할 때 올바르지 않을 수 있습니다. 예 :

struct MyStruct
{
   ...
   myStruct(IDictionary<int, MyStruct> d)
   {
     d.TryGetValue(23, out this);
   }
}

만약myDictionary~을 식별하다IDictionary<TKey,TValue>C #이외의 언어로 작성된 구현MyStruct s = new MyStruct(myDictionary);임무처럼 보이면 잠재적으로 떠날 수 있습니다.s수정되지 않은.

VB.NET으로 작성된 생성자는 C #의 경우와 달리 호출 된 메서드에서out매개 변수를 지정하고 모든 필드를 무조건 지 웁니다. 위에 언급 한 이상한 행동은 VB에서 전체적으로 또는 C #으로 완전히 작성된 코드에서는 발생하지 않지만 C #으로 작성된 코드가 VB.NET으로 작성된 메서드를 호출 할 때 발생할 수 있습니다.


0

매개 변수를 ref로 전달하려면 함수에 매개 변수를 전달하기 전에 매개 변수를 초기화해야합니다. 다른 컴파일러에서는 오류를 표시합니다. 그러나 out 매개 변수의 경우 객체 매개 변수를 전달하기 전에 객체 매개 변수를 초기화 할 필요가 없습니다. 메서드를 호출 할 수 있습니다. 호출 메서드 자체에서 개체를 초기화 할 수 있습니다.


-1

나는 놀고 있었다.ref이 예제가 꽤 흥미 롭다는 것을 알게되었습니다. 나는RefEater(ref s1);두 번째 주석 처리 된 경우와 같이 빌드 오류가 발생하지만s1필드는 생성자가 호출되기 전에 기본값으로 초기화됩니다.https://stackoverflow.com/a/1920659/5612780).

public class Class1
{
    // this will have the default value
    private string s1;

    public Class1()
    {
        // no issue here..
        RefEater(ref s1);

        // Error CS0165 Use of unassigned local variable 's2'
        //string s2;
        //RefEater(ref s2);
    }

    private void RefEater(ref string s)
    {

    }
}


  • s1은 기본적으로 null로 초기화됩니다. 필드가 기본값으로 초기화되고 참조 유형의 기본값이 null이므로 그것이 결코 어떤 문제도 일으키지 않는 이유. - Ankit Rana

-3

나는 이것에 대해서는별로 좋지 않을 수도 있지만, 확실하게 문자열 (비록 기술적으로 참조 형이고 힙에 살지만)은 참조가 아니라 값으로 전달됩니까?

        string a = "Hello";

        string b = "goodbye";

        b = a; //attempt to make b point to a, won't work.

        a = "testing";

        Console.WriteLine(b); //this will produce "hello", NOT "testing"!!!!

이 때문에 함수의 범위를 벗어나는 변경 사항을 원할 경우 ref가 필요합니다. 그렇지 않은 경우에는 참조를 전달하지 않습니다.

지금까지 내가 아는 한 struct / value 유형과 문자열 자체에 대한 ref 만 필요합니다. string은 값 유형이 아니지만 위조하는 참조 유형입니다.

나는 완전히 여기에서 틀릴 수 있었다, 나는 새롭다.


  • 에드윈 Stack Overflow에 오신 것을 환영합니다. 문자열은 다른 객체와 마찬가지로 참조로 전달됩니다. 문자열은 변경 불가능한 객체이므로 혼동 될 수 있으므로 참조로 전달 된 문자열이 명확하지 않습니다. 문자열에 다음과 같은 메서드가 있다고 상상해보십시오.Capitalize()문자열의 내용을 대문자로 바꿉니다. 너가 그 때 너의 선을 대체하면a = "testing";a.Capitalize();출력은 "Hello"가 아닌 "HELLO"가됩니다. 변경할 수없는 형식의 장점 중 하나는 참조를 전달할 수 있으며 값을 변경하는 다른 코드에 대해 걱정할 필요가 없다는 것입니다. - Don Kirkby
  • 유형이 드러 낼 수있는 세 가지 기본 유형의 의미론 : 가변적 인 참조 의미론, 가변적 인 가치 의미론 및 불변의 의미론이 있습니다. 필드 또는 특성 m을 갖는 유형 T의 변수 x 및 y를 고려하고 x가 y로 복사된다고 가정합니다. T가 참조 의미론을 가지고 있다면, x.m의 변화는 y.m에 의해 관찰 될 것이다. T가 가치 의미론을 가지고 있다면, y.m에 영향을 미치지 않고 x.m을 변경할 수있다. T가 불변의 의미를 갖는다면, x.m이나 y.m도 변하지 않을 것이다. 불변의 시멘틱스는, 참조 오브젝트 또는 값 오브젝트에 의해 시뮬레이트 될 수 있습니다. 문자열은 불변 참조 객체입니다. - supercat

-3

함수 내부에서 전달되는 참조 매개 변수가 직접적으로 작동한다는 것을 명심하십시오.

예를 들어,

    public class MyClass
    {
        public string Name { get; set; }
    }

    public void Foo()
    {
        MyClass myObject = new MyClass();
        myObject.Name = "Dog";
        Bar(myObject);
        Console.WriteLine(myObject.Name); // Writes "Dog".
    }

    public void Bar(MyClass someObject)
    {
        MyClass myTempObject = new MyClass();
        myTempObject.Name = "Cat";
        someObject = myTempObject;
    }

이것은 고양이가 아니라 개를 쓸 것입니다. 따라서 someObject에 직접 작업해야합니다.


  • 여기있는 모든 것은 사실이지만 가치에 의한 참조 또는 제외의 차이를 실제로 설명하지는 않습니다. 기껏해야 반은 참조 형과 값 / 불변 형의 차이점을 설명합니다. - Conrad Frix

연결된 질문


관련된 질문

최근 질문