Pass by Value
using System;
using static System.Console;
namespace thistiscsharp
{
class Calculator
{
public static int Plus (int a, int b)
{
Console.WriteLine("Input : {0}, {1}", a, b);
int result = a + b;
return result;
}
}
class MainApp
{
public static void Main(string[] args)
{
int x=3;
int y=4;
int result = Calculator.Plus(x, y);
}
}
}
서론
호출하는 입장인 MainApp클래스의 x, y = 인수 (Arguments)이고
호출되는 메소드를 가지고 있는 Calculator클래스의 a, b = 매개변수(Parameters)이다
그렇다면 메소드에 인수로 넘겨진 x, y는 실제로 Calculator.Plus() 메소드 안으로 들어가는 걸까?
아니다.
매개변수도 독립적인 변수이고 한 변수( 인수) 를 또 다른 변수(매개변수) 에 할당하면 변수가 담고 있는 데이터만 복사 될 뿐이다
using System;
using static System.Console;
namespace thistiscsharp
{
class MainClass
{
public static void Swipe(int a, int b)
{
int c = b;
b = a;
a = c;
}
public static void Main(string[] args)
{
int x=3;
int y=4;
Swipe(x, y);
Console.WriteLine($"{x}, {y}"); //Swipe()를 적용한 후 Main클래스의 x, y는
//4, 3으로 변경 되었을까? => X
}
}
}
이처럼 메소드를 호출할 때 데이터를 복사해서 매개변수에 넘기는 것을 "값에 의한 전달" (Pass by value)라고 부릅니다
Pass by Reference
1. 매개변수를 메소드에 참조로 전달하는 방법
앞의 Pass by Value(값에 의한 전달)에선 두 매개변수의 값을 (x, y)를 교환하지 못한다
인자 x,y (3,4)의 값을 복사한 값이 Swipe()의 매개변수로 들어가고,
값 형식이었으니 Swipe()에서 매개변수 a,b 값을 아무리 바꿔줘도 코드블럭이 끝나는 시점에 바뀐 값이 날라가버린다.
(그 이유는 stack과 heap 게시글 참고 https://zizh.tistory.com/31)
그렇다면 두 매개변수의 값을 제대로 교환할 수 있도록 하는 방법은 없을까?
즉, 복사가 아니라 원본을 사용할 방법은 없을까?
바로 매개변수를 "참조에 의한 전달" (Pass by Reference)로 넘기면 된다
값에 의한 전달이 매개변수가 변수나 상수로부터 값을 복사하는 것과 달리,
참조에 의한 전달은 매개변수가 메소드에 넘겨진 원본 변수를 직접 참조한다
따라서 메소드 안에서 매개변수를 수정하면 이 매개변수가 참조하고 있는 "원본 변수에 수정"이 이루어진다
추가설명 :
앞의 값에 의한 전달은 Swap을 해도 코드블럭이 끝나는시점에 값이 날라간다. 스택구조니까.
하지만 ref를 붙여 참조로 다뤘기 때문에
Swap()메소드의 매개변수는 는 원본 변수 (x,y)값을 복사해서 가져오는게 아니라,
원본 변수를 참조한다(= 원본 변수의 위치를 주소로 가리킨다! )
그래서 Swap()메소드를 실행시키면 원본 변수를 가리키고 있는 화살표를 바꿔주는 거기 떄문에(참조가 바뀌었기 때문에)
"원본 변수에 수정" 이 이루어지는 것임
말이 헷갈리면, 참조라는 말을 실제값을 가리키는 주소라고 생각하면 된다 (생각이아니라 이게 맞음)
참조로 반환한다, 참조로 다룬다, 참조를 전달한다
= 데이터가 저장된 힙 메모리의 주소를 반환한다, 주소를 다룬다, 주소를 전달한다로 바꿔생각
사용 방법:
① 메소드의 선언에서 ref 키워드를 매개변수 앞에 붙여준다.
② 메소드를 호출할 때 다시 ref키워드를 매개변수 앞에 붙여준다.
참조 1
using System;
using static System.Console;
namespace thistiscsharp
{
class MainClass
{
public static void Swipe(ref int a, ref int b) //① 메소드 선언 시에 매개변수 앞 ref추가
{
int c = b;
b = a;
a = c;
}
public static void Main(string[] args)
{
int x=3;
int y=4;
Swipe(ref x, ref y); //② 호출할 때도 매개변수 앞에 ref
Console.WriteLine($"{x}, {y}"); //원본 변수가 바뀌어 x = 4, y = 3 출력
}
}
}
2. 메소드의 결과(return값) 를 참조로 반환하는 참조 반환값(ref return)
참조 반환값을 사용하면 메소드의 호출차로 하여금 반환받은 값을 참조로 다룰 수 있도록 한다.
사용 방법:
메소드 만들 때 :
① ref 한정자를 이용해서 메소드를 선언한다.
② return문이 반환하는 변수 앞에도 ref 키워드를 명시한다.
호출 할 때 :
③ 결과를 담는 지역변수와 호출할 메소드의 이름앞에 ref키워드를 위치시킨다.
class SomeClass
{
int SomeValue = 10;
public ref int SomeMethod()
{
//...구현부...
return ref SomeValue; //결과적으로 이 SomeValue를 참조로 다루는게 목적이다!!
}
}
SomeMethod()는 참조로 반환하도록 구현됐지만, 호출자가 특별한 키워드(그니까 ref) 를 사용하지 않는 한 ' 값 ' 으로 반환하는 평범한 메소드처럼 동작한다
즉, 호출할 때 ③ 의 과정을 하지않고 일반 메소드호출하는 것처럼 하면 그냥 평범하게 값을 반환하는 메소드처럼 동작한다.
SomeClass obj = new SomeClass();
int result = obj.SomeMethod(); //평범한 메소드처럼 값으로 반환됨
그럼 원래 목적인 메소드의 결과(return값)를 참조로 반환하기 위해선 ③ 을 사용하여 다음과 같이 하면 된다
③ 결과를 담는 지역변수와 호출할 메소드의 이름앞에 ref키워드를 위치시킨다.
참고로 이렇게 참조로 반환받은 결과를 담는 지역변수를 참조지역변수라 부른다
SomeClass obj = new SomeClass();
ref int result = ref obj.SomeMethod(); //result는 참조 지역 변수
결과적으로 위의 return값인 SomeValue을 참조로 다루는게 목적이다.
그렇게 되면 참조로 반환받은 결과를 참조 지역 변수인 ref int result에 넣게 되고,
이 result의 값은 Main클래스에서 마음대로 바꿔줄수 있는 것이다
Pass by Value
using System;
using static System.Console;
namespace thistiscsharp
{
class Calculator
{
public static int Plus (int a, int b)
{
Console.WriteLine("Input : {0}, {1}", a, b);
int result = a + b;
return result;
}
}
class MainApp
{
public static void Main(string[] args)
{
int x=3;
int y=4;
int result = Calculator.Plus(x, y);
}
}
}
서론
호출하는 입장인 MainApp클래스의 x, y = 인수 (Arguments)이고
호출되는 메소드를 가지고 있는 Calculator클래스의 a, b = 매개변수(Parameters)이다
그렇다면 메소드에 인수로 넘겨진 x, y는 실제로 Calculator.Plus() 메소드 안으로 들어가는 걸까?
아니다.
매개변수도 독립적인 변수이고 한 변수( 인수) 를 또 다른 변수(매개변수) 에 할당하면 변수가 담고 있는 데이터만 복사 될 뿐이다
using System;
using static System.Console;
namespace thistiscsharp
{
class MainClass
{
public static void Swipe(int a, int b)
{
int c = b;
b = a;
a = c;
}
public static void Main(string[] args)
{
int x=3;
int y=4;
Swipe(x, y);
Console.WriteLine($"{x}, {y}"); //Swipe()를 적용한 후 Main클래스의 x, y는
//4, 3으로 변경 되었을까? => X
}
}
}
이처럼 메소드를 호출할 때 데이터를 복사해서 매개변수에 넘기는 것을 "값에 의한 전달" (Pass by value)라고 부릅니다
Pass by Reference
1. 매개변수를 메소드에 참조로 전달하는 방법
앞의 Pass by Value(값에 의한 전달)에선 두 매개변수의 값을 (x, y)를 교환하지 못한다
인자 x,y (3,4)의 값을 복사한 값이 Swipe()의 매개변수로 들어가고,
값 형식이었으니 Swipe()에서 매개변수 a,b 값을 아무리 바꿔줘도 코드블럭이 끝나는 시점에 바뀐 값이 날라가버린다.
(그 이유는 stack과 heap 게시글 참고 https://zizh.tistory.com/31)
그렇다면 두 매개변수의 값을 제대로 교환할 수 있도록 하는 방법은 없을까?
즉, 복사가 아니라 원본을 사용할 방법은 없을까?
바로 매개변수를 "참조에 의한 전달" (Pass by Reference)로 넘기면 된다
값에 의한 전달이 매개변수가 변수나 상수로부터 값을 복사하는 것과 달리,
참조에 의한 전달은 매개변수가 메소드에 넘겨진 원본 변수를 직접 참조한다
따라서 메소드 안에서 매개변수를 수정하면 이 매개변수가 참조하고 있는 "원본 변수에 수정"이 이루어진다
추가설명 :
앞의 값에 의한 전달은 Swap을 해도 코드블럭이 끝나는시점에 값이 날라간다. 스택구조니까.
하지만 ref를 붙여 참조로 다뤘기 때문에
Swap()메소드의 매개변수는 는 원본 변수 (x,y)값을 복사해서 가져오는게 아니라,
원본 변수를 참조한다(= 원본 변수의 위치를 주소로 가리킨다! )
그래서 Swap()메소드를 실행시키면 원본 변수를 가리키고 있는 화살표를 바꿔주는 거기 떄문에(참조가 바뀌었기 때문에)
"원본 변수에 수정" 이 이루어지는 것임
말이 헷갈리면, 참조라는 말을 실제값을 가리키는 주소라고 생각하면 된다 (생각이아니라 이게 맞음)
참조로 반환한다, 참조로 다룬다, 참조를 전달한다
= 데이터가 저장된 힙 메모리의 주소를 반환한다, 주소를 다룬다, 주소를 전달한다로 바꿔생각
사용 방법:
① 메소드의 선언에서 ref 키워드를 매개변수 앞에 붙여준다.
② 메소드를 호출할 때 다시 ref키워드를 매개변수 앞에 붙여준다.
참조 1
using System;
using static System.Console;
namespace thistiscsharp
{
class MainClass
{
public static void Swipe(ref int a, ref int b) //① 메소드 선언 시에 매개변수 앞 ref추가
{
int c = b;
b = a;
a = c;
}
public static void Main(string[] args)
{
int x=3;
int y=4;
Swipe(ref x, ref y); //② 호출할 때도 매개변수 앞에 ref
Console.WriteLine($"{x}, {y}"); //원본 변수가 바뀌어 x = 4, y = 3 출력
}
}
}
2. 메소드의 결과(return값) 를 참조로 반환하는 참조 반환값(ref return)
참조 반환값을 사용하면 메소드의 호출차로 하여금 반환받은 값을 참조로 다룰 수 있도록 한다.
사용 방법:
메소드 만들 때 :
① ref 한정자를 이용해서 메소드를 선언한다.
② return문이 반환하는 변수 앞에도 ref 키워드를 명시한다.
호출 할 때 :
③ 결과를 담는 지역변수와 호출할 메소드의 이름앞에 ref키워드를 위치시킨다.
class SomeClass
{
int SomeValue = 10;
public ref int SomeMethod()
{
//...구현부...
return ref SomeValue; //결과적으로 이 SomeValue를 참조로 다루는게 목적이다!!
}
}
SomeMethod()는 참조로 반환하도록 구현됐지만, 호출자가 특별한 키워드(그니까 ref) 를 사용하지 않는 한 ' 값 ' 으로 반환하는 평범한 메소드처럼 동작한다
즉, 호출할 때 ③ 의 과정을 하지않고 일반 메소드호출하는 것처럼 하면 그냥 평범하게 값을 반환하는 메소드처럼 동작한다.
SomeClass obj = new SomeClass();
int result = obj.SomeMethod(); //평범한 메소드처럼 값으로 반환됨
그럼 원래 목적인 메소드의 결과(return값)를 참조로 반환하기 위해선 ③ 을 사용하여 다음과 같이 하면 된다
③ 결과를 담는 지역변수와 호출할 메소드의 이름앞에 ref키워드를 위치시킨다.
참고로 이렇게 참조로 반환받은 결과를 담는 지역변수를 참조지역변수라 부른다
SomeClass obj = new SomeClass();
ref int result = ref obj.SomeMethod(); //result는 참조 지역 변수
결과적으로 위의 return값인 SomeValue을 참조로 다루는게 목적이다.
그렇게 되면 참조로 반환받은 결과를 참조 지역 변수인 ref int result에 넣게 되고,
이 result의 값은 Main클래스에서 마음대로 바꿔줄수 있는 것이다