C#에서 readonly 키워드는 필드가 "한 번만 초기화될 수 있다"는 의미를 갖습니다. 많은 개발자들이 이 키워드를 단순히 "변경 불가"로 이해하지만, 참조 타입에 적용되었을 때는 조금 다르게 동작한다는 점을 놓치는 경우가 많습니다.
이 글에서는 readonly 키워드가 값 타입과 참조 타입에서 어떻게 다르게 작동하는지, 그리고 참조는 고정되지만 내부 값은 바뀔 수 있다는 사실을 예제와 함께 정리합니다.
값 타입에서의 readonly
readonly가 값 타입(int, float, bool 등) 에 붙으면, 해당 변수는 초기화된 값을 절대 변경할 수 없습니다.
readonly int number = 10;
number = 20; // ❌ 컴파일 오류 - 값 변경 불가
값 타입은 변수 자체가 데이터를 직접 저장하기 때문에, readonly는 값 자체를 고정합니다.
참조 타입에서의 readonly
private readonly string[] wordList;
참조 타입 (배열, 클래스 등) 에 readonly를 붙이면, 변수에 저장된 참조(주소)를 변경할 수 없게 됩니다. 즉, 한 번 어떤 객체나 배열을 참조하게 되면, 다른 객체로 바꾸는 것은 불가능합니다.
하지만 참조 대상(객체, 배열)의 내부 값은 여전히 변경 가능합니다!
생성자에서만 초기화 가능
public WordWarrior()
{
wordList = new string[] { "apple", "banana" }; // ✅ 생성자 안에서는 초기화 가능
}
public void ResetWords()
{
wordList = new string[] { "grape", "lemon" }; // ❌ 오류: 생성자 밖에서는 재할당 불가
}
readonly 필드는 생성자 내부에서만 한 번 초기화할 수 있습니다. 이후에는 참조를 변경할 수 없습니다.
참조 대입은 불가능
readonly string[] currentWords = new string[] { "sun", "moon", "stars" };
string[] newWords = new string[] { "ocean", "mountain" };
currentWords = newWords; // ❌ 불가능: 참조 자체를 바꿀 수 없음
readonly는 참조 변수의 주소값을 변경할 수 없도록 제한합니다. 따라서 다른 참조 변수나 새로운 배열을 대입하는 것도 불가능합니다.
배열 내부 값은 수정 가능
wordList[0] = "updated"; // ✅ 가능
참조는 바꿀 수 없어도, 참조하고 있는 배열의 내부 데이터는 얼마든지 수정 가능합니다. 이 점에서 readonly는 "불변"과는 다르며, 단지 참조의 이동만 막는 역할을 한다고 이해하면 됩니다.
핵심 정리
* readonly 는 변수의 값을 바꾸지 못하게 막는 키워드입니다.
* 값 타입(int, float 등) 은 변수 자체가 데이터를 담고 있어서 값 변경이 금지됩니다.
* 참조 타입(array, class 등) 은 변수의 값이 주소이기 때문에 참조(주소)만 고정되고, 참조 대상의 내부 값은 변경 가능합니다.
* 생성자에 한해서 한 번 변경할 수 있기 때문에, 초기화는 보통 생성자에서 수행합니다.
그렇다면, const 와의 차이점
const는 컴파일 시점에 값이 고정되는 상수입니다.
선언과 동시에 반드시 값을 설정해야 하며, 숫자나 문자열 같은 단순한 값에만 사용할 수 있습니다.
반면 readonly는 런타임에 한 번만 값을 설정할 수 있고, 배열이나 클래스처럼 조금 더 복잡한 타입에도 사용할 수 있는 장점이 있습니다.
예를 들면,
const string[] colors = { "red", "green" }; // ❌ 불가능
그래서 const는 절대 변하지 않는 숫자나 문자열 같은 값에, readonly 는 한 번 설정해두고 유지되어야 하는 배열이나 객체에 적합합니다.
마무리
readonly는 단순히 "변경 금지" 키워드가 아닙니다. 값 타입과 참조 타입에서 전혀 다르게 작동하며, 특히 참조 타입에서는 내부 값을 얼마든지 바꿀 수 있다는 점을 기억해야 합니다. 값 자체가 중요한 경우에는 const를 사용하고, 객체 참조만 고정하고 내부는 유연하게 관리하고 싶을 때는 readonly를 사용하는 것이 적절합니다.
'C#' 카테고리의 다른 글
int.TryParse() 와 Convert.ToInt32() 중 어떤 걸 써야하나? 고민된다면 (0) | 2025.04.02 |
---|---|
C# 에서 ref, out, in 키워드 정리 (0) | 2025.04.02 |
List<T> 의 동작 방식 (0) | 2025.03.16 |
람다 표현식을 사용할 때 헤깔리는 이유 (0) | 2025.03.15 |
delegate 를 기반으로 한 상태 기계 구현해보기 (0) | 2025.03.12 |