C#을 하다보면 자주 쓰게 되는 ref, out, in 키워드. 정확히 어떤 역할일까?
이 셋은 매개변수 한정자라고 한다. 글자 그대로 매개변수를 어떤 역할로 한정시켜준다.
●ref
C++에서 & 참조 연산자와 비슷한 역할이다.
ref 키워드를 사용하면 call by reference를 명시적으로 할 수 있다.
ref 키워드를 붙이면 기존 변수의 별명이 되어서 수정하게 되면 원래 변수도 변하게 된다. 이름만 다르지 기존 변수 그대로 가져다 쓴다고 생각해도 된다.
값 타입의 경우 명시적으로 call by reference가 되니 확실한 차이가 있다.
참조타입처럼 원본이 수정될 수 있다는 점도 있겠지만 또 하나 중요한 것은 boxing이 일어나지 않는다는 것. 이점 때문에 참조 타입과 다르다.
※ boxing과 unboxing은 쉽게 말해 casting이다. C#의 모든 객체는 object를 상속 받으니 object 객체로 포장해서 만드는게 boxing이고 object 객체에서 포장 벗기고 내용물 꺼내는게 unboxing이다.
값 타입을 손쉽게 참조타입으로 만들었다가 다시 값 타입으로 만들 수 있게 되는 것이지만 박싱, 언박싱에 드는 비용이 굉장히 크니까 안 쓰는게 좋다.
ref를 사용하면 이 박싱/언박싱 과정이 일어나지 않는다. 사용하게 되면 컴파일 에러가 나온다.
예를 들어 object형 매개변수를 받는 메소드에 int형 인자를 넘겨주면 평소에는 박싱, 언박싱이 일어나지만 ref를 붙이는 순간 에러다.
참조타입의 경우 ref를 쓴 것과 안 쓴 것의 차이가 뭘까?
참조타입은 ref가 없어도 매개변수로 넘겨주면 원본의 값이 바뀌기 때문에 차이점을 바로 알기 어려울 수 있다.
참조 타입은 ref가 없다면 call by value를 하는데 이는 스택에 있는 값을 그대로 복사한 새로운 변수가 생기는 것이다.
스택에는 힙의 메모리 주소가 담겨있을 테니 힙에 있는 동일한 객체를 가리키지만 스택에는 두 개의 변수가 존재하는 것.
C++로 설명하면 포인터는 2개인데 객체는 하나를 동시에 가리키는 경우가 되겠다.
그러나 ref 키워드를 사용하면 call by reference가 되면서 별칭이 생길 뿐 스택에 새 변수가 생기는 것이 아니다. 포인터 1개에 객체 하나를 가리키게 된다.
ref의 사용 방법은 2가지다.
1. 시그니처에서 매개변수에 ref 사용
ex) public void SetData(ref object data) { }
시그니처에서도 ref를 써야 하고 해당 메소드를 호출할 때 매개변수에도 ref를 붙여줘야 한다.
ex) object data = 5;
객체.SetData(ref data); // 호출할 때도 ref 작성.
* 매개변수로 넘겨주는 경우 ref를 사용하기 위해선 반드시 초기화가 되어있어야 한다.
2. 시그니처에서 리턴타입에 ref 사용
ex) public ref object GetData() { return ref data}
이 경우 호출할 때도 호출자와 메소드 둘 다 ref를 붙여서 리턴을 받아야 한다.
ex) ref object data = ref 객체.GetData();
●out
out은 ref를 출력용으로만 사용하는 것과 같다. 사용 방식은 ref의 1번과 동일하다.
ref와 다른 점은 out은 출력용 매개변수 한정자이기 때문에 메소드 내부에서 반드시 값을 지정해줘야 한다. 안하면 컴파일 에러가 발생한다. 또한 out 변수는 메소드 내부에서 읽을 수 없다. 출력 전용이기 때문에 읽으면 마찬가지로 컴파일 에러가 발생한다.
이 점 때문에 인자로 넘겨줄 때 out을 지정하는 인수는 초기화가 되어있지 않아도 괜찮다. 메소드 내부에서 반드시 값을 지정하기 때문.
ref의 용도를 출력으로 한정지어서 에러를 줄이고 가독성을 높이기 위한 키워드라고 생각하면 편하다.
●in
in 은 out과 반대다 사용 방식은 ref와 동일하다. 여기서 call by reference를 위해 쓰이는 in은 foreach문 등 에서 쓰이는 in과 약간 다르다.
만약 리턴을 읽기 전용의 ref 값으로 보내고 싶다면 in을 사용하는게 아니라 시그니처에 ref readonly를 사용해야 한다.
이 경우 호출자는 반환된 ref 값을 복사하거나 수정할 수 없다.
C++ 식으로 생각하면 in은 const &와 비슷하겠다.
'부트캠프' 카테고리의 다른 글
Unity TextMeshPro (0) | 2023.07.25 |
---|---|
정규표현식 (0) | 2023.07.24 |
C# 문자열 보간($) (0) | 2023.07.18 |
C# Nullable Reference Type (0) | 2023.07.18 |
C#에서 클래스의 크기와 메모리 패딩 (0) | 2023.07.18 |