C# ref 완전 정리
ref 는 값이 저장된 위치 ( 메모리 주소 ) 를 직접 전달하는 키워드이다.
호출자가 가진 변수를 복사하지 않고 그 원본을 그대로 함수나 다른 변수에게 넘긴다
- 수정 가능 : 피호출자가 값을 바꾸면 호출자 변수도 함께 바뀐다
- 복사 비용 절감 : 특히 큰 struct ( 값 형식 ) 전달 시 복사 오버헤드 감소
- out : 반드시 초기화해서 돌려주기 ( 입력은 의미 없다 )
- in : 읽기 전용 ( by - ref 로 가져오되 수정 금지 , 복사 최소화 )
- ref : 읽고 / 쓰고 모두 가능 ( 원본 수정 )
1. 매개변수로 사용
void Foo(ref int x) { x += 10; }
int a = 5;
Foo(ref a); // a == 15
호출부에도 ref 가 필요하다 ( 둘 다 작성해야 한다 )
2. ref 지역변수 ( ref local )
int[] arr = { 1, 2, 3 };
ref int r = ref arr[1]; // r은 arr[1]의 "별칭"
r = 42; // arr[1] == 42
3. ref 반환 ( ref return )
ref int Find(ref int[] xs, int value) {
for (int i = 0; i < xs.Length; i++)
if (xs[i] == value) return ref xs[i]; // 요소 "주소"를 반환
throw new InvalidOperationException();
}
int[] data = { 10, 20, 30 };
ref int spot = ref Find(ref data, 20);
spot = 99; // data[1] == 99
반환 타입 앞 , return 에도 ref 가 필요하다
4. ref readonly
주소는 넘기되 읽기 전용으로 보장한다 ( 수정 불가 , 복사도 회피 )
ref readonly int ro = ref arr[0];
5. in / out
- ref T : read / write by - ref ( 초기화된 값 요구 )
- in T : read - only by - ref ( 초기화된 값 요구 , 복사 최소화 )
- out T : write - only by - ref ( 호출 전 초기화 불필요 , 반드시 설정해서 반환 )
6. ref struct , ref readonly struct
- Span<T> 처럼 스택 한정 타입 , 힙으로 못나간다 ( 캡처 / 박싱 금지 )
- 성능 안전 ( 범위 제약 ) 목적 , ref 와 자주 함께 등장한다
예시 코드
▼ Swap
static void Swap(ref int a, ref int b)
{
int tmp = a;
a = b;
b = tmp;
}
int x = 1, y = 2;
Swap(ref x, ref y); // x=2, y=1
▼ 큰 구조체 복사 줄이기
struct Big
{
public fixed byte buffer[1024]; // 예시: 매우 큰 값 형식
}
static void Touch(ref Big b) { /* b 수정 */ }
Big big = default;
Touch(ref big); // 큰 복사 없음(주소만 전달)
▼ ref return 으로 컬렉션 내부 직접 수정
static ref int ElementRef(int[] xs, int index)
{
if ((uint)index >= (uint)xs.Length) throw new ArgumentOutOfRangeException();
return ref xs[index];
}
int[] a = { 5, 6, 7 };
ref int e = ref ElementRef(a, 2);
e++; // a[2] == 8
▼ ref readonly 로 안전하게 노출
static ref readonly int MaxRef(in int x, in int y)
=> ref (x >= y ? ref x : ref y);
int i = 10, j = 20;
ref readonly int m = ref MaxRef(in i, in j);
// m = 0; // 컴파일 에러( 읽기 전용 )
Console.WriteLine(m); // 20
▼ foreach ref + Span<T> 로 in - place 변환
int[] nums = { 1, 2, 3, 4 };
Span<int> s = nums;
foreach (ref int v in s)
v *= 2; // 원본 배열이 직접 수정됨
// nums == {2,4,6,8}
주의할 점
- 호출부에도 ref 를 명시해야 한다 ( 헷갈리면 컴파일 에러로 알려준다 )
- ref 인수는 변수여야 하며 , 읽기 / 쓰기 가능한 저장 위치여야 한다
- ref 매개변수는 호출 시 이미 초기화되어 있어야 한다 ( out 과 다르다 )
- 선택적 매개변수 ( 기본값 ) 로 ref / oun / in 은 사용할 수 없다
- ref 로 넘긴 값을 여기저기서 수정하면 가시성 / 추적이 어려워진다
정리
ref 는 원본 값의 주소를 직접 넘겨서 복사 없이 읽고 쓰게 해주는 키워드이다.
큰 struct 성능 최적화와 in - place 수정에 유용하지만
수명 , 불변성 , 쓰레드 안전을 꼭 관리해야 한다.
'⭐C Sharp > 10. 참조' 카테고리의 다른 글
| 참조 ( Reference Type ) (0) | 2025.09.28 |
|---|