C#에서 const와 readonly 키워드는 모두 한 번 선언되면 수정할 수 없는 불변(immutable) 값을 정의하는 데 사용됩니다. 하지만 두 키워드 사이에는 몇 가지 중요한 차이점이 존재합니다.
const란?
const 한정자는 컴파일 시점에 값이 확정되며 이후 변경되지 않는 상수를 선언합니다. C#에서는 기본 제공 타입(built-in types)만 const로 지정할 수 있으며, 클래스나 구조체 같은 사용자 정의 타입은 const로 선언할 수 없습니다. 또한 메서드, 프로퍼티, 이벤트 같은 클래스 멤버에도 const를 적용할 수 없습니다.
const 상수는 반드시 선언과 동시에 초기화해야 합니다.
class Period{
public const int hours = 12;
public const int minutes = 60;
}const는 private, public, protected, protected internal, private protected 등 모든 접근 제한자와 함께 사용할 수 있습니다.
또한 const는 암묵적으로 static처럼 동작합니다. 즉, 상수의 값은 클래스의 모든 인스턴스에서 동일합니다. 별도로 static 키워드를 붙일 필요가 없으며, 인스턴스 변수를 통해서는 접근할 수 없고 반드시 클래스 이름을 통해 접근해야 합니다.
readonly란?
readonly로 표시된 필드는 선언 시점 또는 생성자 내부에서만 값을 할당할 수 있습니다. 클래스 인스턴스가 생성된 이후에는 readonly 필드를 수정할 수 없습니다.
필드가 값 타입(value type)이라면 readonly를 붙이는 순간 해당 필드는 불변이 됩니다. 반면 참조 타입(reference type)인 경우에는 변수가 참조하는 객체의 내부 데이터는 여전히 변경할 수 있습니다. 다만 그 참조 자체를 새로운 객체를 가리키도록 바꾸는 것은 불가능합니다.
class Person{
private readonly string _title;
private readonly string _skill;
public Person(string title, string skill){
_title = title;
_skill = skill;
}
}readonly 필드는 필드 선언부와 각 생성자에서 여러 번 할당될 수 있으며, 어떤 생성자가 사용되었는지에 따라 서로 다른 값을 가질 수도 있다는 점이 특징입니다.
어셈블리 관점에서의 핵심 차이
두 키워드의 가장 중요한 차이점은 한 어셈블리(assembly)에 선언된 const 또는 readonly 필드가 다른 어셈블리에서 사용될 때 나타납니다.
const의 경우: 마치 찾아 바꾸기(find-replace)처럼 동작합니다. 상수 값이 두 번째 어셈블리의 IL(중간 언어) 코드에 직접 '구워져(baked into)' 들어갑니다. 따라서 상수 값을 업데이트하더라도 두 번째 어셈블리를 다시 컴파일하기 전까지는 이전 값이 유지됩니다.
readonly의 경우: 메모리 위치에 대한 참조처럼 동작합니다. 값이 두 번째 어셈블리의 IL 코드에 포함되지 않기 때문에, 메모리 위치의 값이 업데이트되면 두 번째 어셈블리는 재컴파일 없이도 새로운 값을 얻게 됩니다. 즉, readonly 필드를 수정하면 첫 번째 어셈블리만 다시 컴파일하면 되고, 사용자 측 어셈블리는 재컴파일할 필요가 없습니다.
예제 코드
using System;
class Program{
static void Main(){
Console.WriteLine(Period.HOURS);
var person = new Person("John", "Programmer");
person.Print();
}
}
class Period{
public const int HOURS = 12;
public const int MINUTES = 60;
}
class Person{
private readonly string _title;
private readonly string _skill;
public Person(string title, string skill){
_title = title;
_skill = skill;
}
public void Change(string skill){
// 오류: readonly 필드에는 할당할 수 없습니다.
// this._skill = skill;
}
public void Print(){
Console.WriteLine($"{_title}: {_skill}");
}
}실행 결과
12 John: Programmer
정리
컴파일 시점에 값이 확정되고 절대 변하지 않는 값이라면 const를, 런타임에 결정되거나 생성자를 통해 초기화해야 하는 값이라면 readonly를 사용하는 것이 좋습니다. 특히 라이브러리를 배포하는 경우, const 값 변경 시 참조하는 모든 어셈블리의 재컴파일이 필요하다는 점을 고려하면 readonly가 더 유연한 선택이 될 수 있습니다.