본문 바로가기
C#

C#] Method Parameters - parameters 전달

by Fastlane 2023. 8. 22.
728x90
반응형

C#에서 arguments는 value 또는 reference로 parameter로 전달될 수 있다. C# types은 reference type(class) 이거나 value type(struct)일 수 있다. 

 

  • value 전달은 변수의 copy를 함수로 전달한다는 의미이다. 
  • reference 전달은 변수 접근을 함수로 전달한다는 의미이다. 
  • reference type의 변수는 데이터의 reference를 포함한다. 
  • value type의 변수는 데이터를 직접 포함한다. 

struct는 value type이기 때문에, 함수에 struct를 전달할 때, 함수는  struct arguments의 copy를 받아 처리한다. 함수는 호출한 함수의 원본 struct에 접근할 수 없으므로, 수정할 수 없다. 함수는 오직 copy만 수정할 수 있다. 

 

class instance는 reference type이기 때문에, 함수에 reference type를 전달할 때, 함수는 class instance의 reference의 copy를 전달받는다. 이말은, 호출된 함수는 instance의 주소의 copy를 받으며, 호출한 함수는 instance의 원본 주소를 갖는다. 양쪽 address모두 동일한 object를 가리킨다. 호출된 함수는 호출한 함수의 class instance의 주소를 수정할 수 없다. 하지만, 호출된 함수는 address의 copy를 이용하여 원본 주소와 주소 reference copy의 class members에 접근할 수 있다. 호출된 함수가 class member를 수정하면, 호출한 함수의 원본 class instance도 같이 변경된다. 

 

class TheClass
{
    public string? willIChange;
}

struct TheStruct
{
    public string willIChange;
}

class TestClassAndStruct
{
    static void ClassTaker(TheClass c)
    {
        c.willIChange = "Changed";
    }

    static void StructTaker(TheStruct s)
    {
        s.willIChange = "Changed";
    }

    public static void Main()
    {
        TheClass testClass = new TheClass();
        TheStruct testStruct = new TheStruct();

        testClass.willIChange = "Not Changed";
        testStruct.willIChange = "Not Changed";

        ClassTaker(testClass);
        StructTaker(testStruct);

        Console.WriteLine("Class field = {0}", testClass.willIChange);
        Console.WriteLine("Struct field = {0}", testStruct.willIChange);

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    Class field = Changed
    Struct field = Not Changed
*/

Pass a value type by value

int n = 5;
System.Console.WriteLine("The value before calling the method: {0}", n);

SquareIt(n);  // Passing the variable by value.
System.Console.WriteLine("The value after calling the method: {0}", n);

// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();

static void SquareIt(int x)
// The parameter x is passed by value.
// Changes to x will not affect the original value of x.
{
    x *= x;
    System.Console.WriteLine("The value inside the method: {0}", x);
}
/* Output:
    The value before calling the method: 5
    The value inside the method: 25
    The value after calling the method: 5
    
    변수 n은 value type이다. data 자체를 포함하며 값은 5이다. 
    SquareIt이 호출될 때, n은 parameter로 copy되고 함수 내부에서 제곱된다. 
    하지만, Main에서 SquareIt호출 후에도 n의 값은 동일하다. 
    method 내부에서 일어난 변경사항은 local variable x에만 영향을 준다. 
*/

Pass a value type by reference

int n = 5;
System.Console.WriteLine("The value before calling the method: {0}", n);

SquareIt(ref n);  // Passing the variable by reference.
System.Console.WriteLine("The value after calling the method: {0}", n);

// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();

static void SquareIt(ref int x)
// The parameter x is passed by reference.
// Changes to x will affect the original value of x.
{
    x *= x;
    System.Console.WriteLine("The value inside the method: {0}", x);
}
/* Output:
    The value before calling the method: 5
    The value inside the method: 25
    The value after calling the method: 25
    
    argument가 ref parameter로 전달된 것만 제외하면, 이전 코드와 동일하다.
    n값은 함수 내부에서 x가 변경될 때 변경된다. 
    n값이 전달된 것이 아니고, n의 reference가 전달되었다. 
    parameter x는 int가 아니며, int, 이 경우에는 n의 reference이다. 
    따라서, x가 함수 내부에서 제곱될 때, n을 참조하는 x가 제곱된 것이다. 
*/

Pass a reference type by value

int[] arr = { 1, 4, 5 };
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);

Change(arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);

static void Change(int[] pArray)
{
    pArray[0] = 888;  // This change affects the original element.
    pArray = new int[5] { -3, -1, -2, -3, -4 };   // This change is local.
    System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}
/* Output:
    Inside Main, before calling the method, the first element is: 1
    Inside the method, the first element is: -3
    Inside Main, after calling the method, the first element is: 888
    
    arr이 reference type이고, ref 없이 전달되었기 때문에, 
    arr의 reference의 copy가 method로 전달되었다. 
    parameter가 arr의 reference의 copy이기 때문에 값을 변경하는 것이 가능하다. 
    하지만, 함수 내부에 new operator를 사용하여 memory의 새 portion을 차지하는 것은 변수 pArray가 새로운 array를 reference하도록 한다. 
    따라서, Main에 생성된 원본 array인 arr에 영향을 주지 못한다. 
    사실, Main에서 하나, Change 함수에서 하나 총 두개의 array가 생성된 것이다. 
*/

Pass a reference type by reference

int[] arr = { 1, 4, 5 };
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);

Change(ref arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);

static void Change(ref int[] pArray)
{
    // Both of the following changes will affect the original variables:
    pArray[0] = 888;
    pArray = new int[5] { -3, -1, -2, -3, -4 };
    System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}
/* Output:
    Inside Main, before calling the method, the first element is: 1
    Inside the method, the first element is: -3
    Inside Main, after calling the method, the first element is: -3
    
    함수 내부에 일어나는 모든 수정사항이 Main의 원본 array에 적용된다. 
    원본 array가 new operator를 이용하여 재위치된다. 
    Change 함수 호출 후, arr의 모든 reference는 Change 함수 내부에서 생성된 five-element array를 가리킨다. 
*/
Passing parameters by value by reference
value type passing a copy of data
함수가 parameter를 다른 object에 할당 : caller는 알 수 없음
함수가 수정한 parameter에 의해 참조된 object : caller는 알 수 없음
passing access of data
함수가 parameter를 다른 object에 할당 : caller는 알 수 없음
함수가 수정한 parameter에 의해 참조된 object : caller는 알 수 있음
reference type 함수가 parameter를 다른 object에 할당 : caller는 알 수 없음
함수가 수정한 parameter에 의해 참조된 object : caller는 알 수 있음
passing access of reference to data
함수가 parameter를 다른 object에 할당 : caller는 알 수 있음
함수가 수정한 parameter에 의해 참조된 object : caller는 알 수 있음

 

parameter 값을 fields에 저장할 수 있다. parameters가 by value로 전달 되었을 때는 안전하다. 값은 복사된다. parameters가 reference로 전달되면 새로운 변수에 언제 저장하는 것이 안전한지  compiler가 정하도록 요구한다. 

compiler는 2 scopes를 사용한다. 

  • safe_to_escape scope : expression 안전하게 접근할 수 있는 scope을 정한다. 
  • ref_safe_to_escape : expression의  reference에 안전하게 접근하거나 수정할 수 있는 scope을 정한다. 

Modifiers

in, ref, out 없이 선언된 Parameters는 by value로 호출된 함수에 전달된다. 

method parameters를 선언할때 사용할 수 있는 keyword는 다음과 같다. 

  • params : 가변수의 argument를 받는다.  
  • in : by reference로 전달되며, 호출된 함수가 읽을 수만 있다. 
  • ref : by reference로 전달되며, 호출된 함수가 읽거나 쓸 수 있다. 
  • out : by reference로 전달되며, 호출된 함수가 쓸 수 있다. 
728x90
반응형

'C#' 카테고리의 다른 글

C# 9.0] init keyword, record, with-expression  (0) 2023.09.05
C#] Method Parameters - params, out  (0) 2023.08.23
C#] type, System.Type, System.Reflection  (0) 2023.06.19
C#] System.Collections.Immutable  (0) 2023.05.18
C#] Asynchronous VS Multithreading  (0) 2023.04.25

댓글