C#에는 왜 전역 변수가 없을까?
C#은 C++과 달리 전역 변수(global variable) 개념을 지원하지 않습니다. 이는 의도적인 언어 설계 결정입니다. C#의 창시자인 앤더스 헤일스버그(Anders Hejlsberg)는 전역 상태가 코드의 예측 가능성을 떨어뜨리고 디버깅을 어렵게 만든다고 보았기 때문입니다.
대신 C#에서는 모든 변수와 메서드가 반드시 클래스나 구조체 같은 타입 내부에, 그리고 그 타입은 반드시 네임스페이스(namespace) 안에 선언되어야 합니다. 이러한 구조 덕분에 코드의 소속 관계가 명확해지고, 이름 충돌(name collision) 문제도 체계적으로 해결할 수 있습니다.
범위 확인 연산자(::)의 역할 변화
C++에서 범위 확인 연산자(scope resolution operator)인 ::는 전역 변수에 접근할 때 자주 사용됩니다. 하지만 C#에서 이 연산자는 전역 변수가 아닌 네임스페이스 식별 용도로 재정의되었습니다. 이를 전역 네임스페이스 별칭(global namespace alias)이라고 부릅니다.
예를 들어, 서로 다른 네임스페이스에 동일한 이름의 타입이 존재하여 이름이 충돌하는 경우, :: 연산자를 사용해 정확히 어떤 타입을 참조할지 명시할 수 있습니다. 최상위(루트) 네임스페이스의 System.Console 클래스를 참조하려면 다음과 같이 작성합니다.
global::System.Console
여기서 global::은 항상 프로그램의 최상위 네임스페이스부터 검색을 시작하도록 컴파일러에 지시합니다. 사용자가 System이라는 이름의 사용자 정의 네임스페이스를 만들었더라도, .NET의 기본 System 네임스페이스와 충돌하지 않고 확실하게 구분할 수 있습니다.
예제 코드
아래 예제는 using 별칭과 :: 연산자, 그리고 global::System.Console을 함께 활용하는 방법을 보여줍니다.
using myAlias = System.Collections;
namespace Program {
class Demo {
static void Main() {
myAlias::Hashtable h = new myAlias::Hashtable();
h.Add("M", "1");
h.Add("N", "2");
h.Add("O", "3");
h.Add("P", "4");
foreach (string n in h.Keys) {
global::System.Console.WriteLine(n + " " + h[n]);
}
}
}
}실행 결과
N 2 O 3 M 1 P 4
* Hashtable은 해시 기반 자료구조이므로 키의 출력 순서는 삽입 순서와 다를 수 있습니다.
정리
C#이 전역 변수를 제공하지 않는 것은 제약이 아니라 장점입니다. 모든 데이터가 타입과 네임스페이스라는 명확한 경계 안에 위치하기 때문에 코드 유지보수성이 높아지고, 테스트가 쉬워지며, 예기치 않은 상태 변경으로 인한 버그를 줄일 수 있습니다. 만약 여러 곳에서 공유해야 하는 값이 필요하다면, 전역 변수 대신 정적(static) 필드나 속성, 싱글턴 패턴, 또는 의존성 주입(DI)을 활용하는 것이 C#의 권장 방식입니다.