주소 - c# 매개변수란



'ref'와 'out'키워드의 차이점은 무엇입니까? (16)

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

public void myFunction(ref MyClass someClass)

public void myFunction(out MyClass someClass)

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


Answer #1

아웃:

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

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

심판 :

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

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

Answer #2

"빵 굽는 사람"

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

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

string s = "Able";

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

s = "Baker";

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

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

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

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

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


Answer #3

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

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

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


Answer #4

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

Out : 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을 작성하는 동안 두 개를 구별하지 않습니다).


Answer #5

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

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

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


Answer #6

나는 ref 을 가지고 노는 중이 ref 예가 아주 흥미 롭다. RefEater(ref s1); 의 호출을 생각했습니다 RefEater(ref s1); 두 번째 주석 처리 된 경우와 같이 빌드 오류가 발생하지만 s1 필드는 생성자가 호출되기 전에 기본값으로 초기화됩니다 ( https://.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)
    {

    }
}

Answer #7

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

        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은 값 유형이 아닌 것으로 보이는 참조 유형이므로 필요하지 않습니다.

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


Answer #8

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


Answer #9

아래에서는 Refout 을 모두 사용하는 예제를 보여 줬습니다 . 자, 여러분 모두는 심판에 대해 밝혀 질 것입니다.

아래에 언급 된 예제에서 나는 // myRefObj = new myClass {Name = "ref outside called !!"}; 행에서 "할당되지 않은 지역 변수 '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; }
} 

Answer #10

예를 들어 (나 같은) 여기 배우는 사람들은 Anthony Kolesov가 말하는 것 입니다.

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

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


Answer #11

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

예를 들어,

    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에 직접 작업해야합니다.



Answer #13

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

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

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

  1. 값은 설정되지 않고 설정 될 때까지 메소드에서 읽을 수 없습니다.
  2. 이 메서드 반환하기 전에 설정 해야합니다 .

Answer #14

refout 다음과 같은 차이점을 제외하고 비슷하게 동작합니다.

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

Answer #15

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

out 은 컴파일러에게 객체의 초기화가 함수의 책임임을 알려주고, 함수는 out 매개 변수에 할당해야합니다. 할당되지 않은 상태로 둘 수는 없습니다.


Answer #16

제작 시간 :

(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 로 전달하여 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 포인터는 방해받지 않습니다).

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

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





ref