ref, out 키워드를 사용하면 매개변수를 "참조에 의한 전달(pass by reference)" 을 할수있다.
using System;
namespace RefReturn
{
class MainApp
{
public static void Swap(int a, int b)
{
int temp = b;
b = a;
a = temp;
}
static void Main(string[] args)
{
int x = 3;
int y = 4;
Console.WriteLine($"x:{x}, y:{y}");
Swap(x, y);
Console.WriteLine($"x:{x}, y:{y}");
}
}
}
위 코드는 Swap() 함수의 두 매개변수의 교환을 수행하지 못한다. 매개변수도 메소드 외부에서 메소드 내부로 데이터를 전달하는 매개체 역활을 할 뿐이지 근본적으로는 변수이기때문이다. 한 변수를 또 다른 변수에 할당하면 변수가 담고있는 데이터만 복사가 될 뿐이다.
메소드내에서 실제 값을 변경하기위해선 "참조에 의한 전달" 을 해야한다. "값에 의한 전달"이 매개 변수가 변수나 상수로부터 값을 복사하는 것과는 달리 "참조에 의한 전달"은 매개변수가 메소드에 넘겨진 원본 변수를 집적 참조한다.
참조에 의한 전달을 하기위해 필요한 키워드가 바로 ref, out 이다. 먼저 ref키워드 사용법에 대해 알아보자. ref키워드는 매개 변수앞에 ref키워드를 붙여준다.
public static void Swap(ref int a, ref int b)
{
int temp = b;
b = a;
a = temp;
}
그리고 메소드를 호출할 때 다시 ref키워드를 매개 변수 앞에 붙여주면 된다.
int x = 3;
int y = 4;
Swap(ref x, ref y);
처음 예제를 ref키워드를 적용시켜 다시 작성해보자.
using System;
namespace RefReturn
{
class MainApp
{
public static void Swap(ref int a, ref int b)
{
int temp = b;
b = a;
a = temp;
}
static void Main(string[] args)
{
int x = 3;
int y = 4;
Console.WriteLine($"x:{x}, y:{y}");
Swap(ref x, ref y);
Console.WriteLine($"x:{x}, y:{y}");
}
}
}
// 결과
// x:3, y:4
// x:4, y:3
이번엔 메소드의 결과를 참조로 반환하는 "참조 반환값"에 대해 살펴보자. 참조 반환값을 이용하면 메소드 호출자로 하여금 반환받은 결과를 참조로 다룰 수 있도록 한다. ref 한정자를 이용해서 메소드를 선언하고 , return 문이 반환하는 변수 앞에도 ref키워드를 명시해야 한다.
class Product
{
private int price = 100;
public ref int GetPrice()
{
return ref price;
}
}
GetPrice() 메소드는 참조로 반환하도록 구현되었지만 호출자가 특별한 키워드를 사용하지 않는 한 값으로 반환하는 평범한 메소드처럼 동작한다. GetPrice() 메소드가 반환하는 결과를 참조로 받고 싶다면 결과를 담는 지역 변수와 호출할 메소드의 이름 앞에 ref 키워드를 사용해야한다. 이렇게 참조로 반환받은 결과를 담는 지역변수를 "참조 지역 변수(ref local)"라고 부른다.
Product obj = new Product();
int result = obj.GetPrice(); // ref 키워드를 사용하지않아 평범한 메소드로 작동
Product obj = new Product();
ref int result = ref obj.GetPrice(); // ref 키워드를 사용해 참조로 반환받음(result는 참조지역변수)
아래는 참조반환값과 참조지역변수를 이용한 간단한 예제이다.
using System;
namespace RefReturn
{
class Product
{
private int price = 100;
public ref int GetPrice()
{
return ref price;
}
public void PrintPrice()
{
Console.WriteLine($"Pirce : {price}");
}
}
class MainApp
{
static void Main(string[] args)
{
Product carrot = new Product();
ref int ref_local_price = ref carrot.GetPrice();
int normal_local_price = carrot.GetPrice();
carrot.PrintPrice();
Console.WriteLine($"Ref Local Price : {ref_local_price}");
Console.WriteLine($"Normal Local Price :{normal_local_price}");
ref_local_price = 200;
carrot.PrintPrice();
Console.WriteLine($"Ref Local Price :{ref_local_price}");
Console.WriteLine($"Normal Local Price :{normal_local_price}");
}
}
}
이번엔 out 키워드에 대해 알아보자. out 키워드의 사용법은 간단하다.
using System;
namespace RefReturn
{
class MainApp
{
static void Divide(int a, int b, out int quotient, out int remainder)
{
quotient = a / b;
remainder = a % b;
}
static void Main(string[] args)
{
int a = 20;
int b = 3;
int c;
int d;
Divide(a, b, out c, out d);
Console.WriteLine("Quotient : {0}, Remainder {1}", c, d);
}
}
}
사용법이나 결과를 보면 ref 키워드와 별 차이점이 없어보이지만 out 은 ref 에는 없는 안전장치가 있다. 예를 들어 ref 키워드를 이용해서 매개 변수를 넘기는 경우에는 메소드가 해당 매개 변수에 결과를 저장하지 않아도 컴파일러는 아무런 경고를 하지 않는다. 이와 달리 out 키워드는 매개 변수를 넘길 때는 메소드가 해당 매개 변수에 결과를 저장하지 않으면 컴파일러가 에러 메시지를 출력한다. 메소드를 호출하는 쪽에서는 초기화하지 않은 지역 변수를 메소드의 out매개 변수로 넘기는것은 가능하다. 컴파일러가 호출당하는 메소드에서 그 지역 변수를 할당할 것을 보장하기 때문이다. 즉 메소드내에서 결과를 할당하지 않는 버그가 생길 가능성을 제거할 수 있다.
참고로 out 키워드는 메소드를 호출하기 전에 미리 선언할 필요가 없다. 호출할 때 매개 변수 목록 안에서 즉석으로 선언할수도 있다.
int a = 20;
int b = 3;
Divide(a, b, out int c, out int d);
'Language > C#' 카테고리의 다른 글
가비지 컬렉션(Garbage Collection)이란 무엇인가? (0) | 2023.05.14 |
---|---|
C# 확장메소드(Extension Method) (0) | 2023.04.16 |
for와 foreach의 콜렉션 접근방식차이 (0) | 2023.04.11 |
C#에서 const, readonly 차이 (0) | 2023.03.29 |