[로봇활용_9주차] C# 정적 생성자와 정적 클래스

최윤호·2025년 10월 4일
post-thumbnail

정적 멤버를 다루는 도구

정적 멤버를 다루다 보면 이런 궁금증이 생길 수 있습니다.

"인스턴스 멤버는 생성자로 초기화하는데, 정적 멤버는 어떻게 초기화하나요?"
"클래스의 모든 멤버를 정적으로만 가지고 있다면, 다룰 방법이 없을까요?"

이 질문들에 대한 해답은 '정적 생성자''정적 클래스'에 있습니다.

1)정적 생성자(Static Constructor)

인스턴스 생성자가 객체를 만들 때마다 호출되어 각 객체를 초기화한다면,
정적 생성자는 해당 클래스가 프로그램에서 처음 사용되는 순간,
CLR에 의해 단 한 번만 호출되어 클래스 자체를 초기화합니다.

[특징]
1. static키워드를 붙여서 만듭니다.
2. 접근 제한자(public, private 등)를 사용할 수 없습니다.
3. 매개변수(parameter)를 가질 수 없습니다.
4. 클래스당 단 하나만 존재할 수 있습니다.
5. CLR에 의해 자동으로 한 번만 호출합니다.
6. 정적 생성자는 코드에서 직접 호출할 수 없습니다.

[코드]

using System;

// 각종 설정 값을 파일에서 딱 한 번만 읽어와야 하는 상황을 가정해 봅시다.
public class GameConfig
{
    // 모든 객체가 공유할 정적 필드
    public static int MaxPlayers { get; private set; }
    public static string Difficulty { get; private set; }

    // 정적 생성자: 이 클래스가 처음 사용될 때 단 한 번 실행됩니다.
    static GameConfig()
    {
        // 설정 파일의 값을 읽어온다고 가정합시다.
        Console.WriteLine("정적 생성자 호출! 설정 파일을 읽어옵니다...");
        MaxPlayers = 100;
        Difficulty = "Hard";
        Console.WriteLine("설정 완료!");
    }

    // 인스턴스 생성자
    public GameConfig()
    {
        Console.WriteLine("인스턴스 생성자 호출!");
    }
}

class Program
{
    static void Main()
    {
        Console.WriteLine("프로그램 시작!");

        // 1. 정적 멤버에 처음 접근하는 순간, 정적 생성자가 호출됩니다.
        Console.WriteLine($"현재 난이도: {GameConfig.Difficulty}");

        Console.WriteLine("---");

        // 2. 인스턴스를 생성해 봅니다.
        GameConfig config1 = new GameConfig();
        GameConfig config2 = new GameConfig();

        // 정적 생성자는 더 이상 호출되지 않습니다.
        Console.WriteLine($"최대 플레이어 수: {GameConfig.MaxPlayers}");
    }
}

[실행 결과]

프로그램 시작!
정적 생성자 호출! 설정 파일을 읽어옵니다...
설정 완료!
현재 난이도: Hard
---
인스턴스 생성자 호출!
인스턴스 생성자 호출!
최대 플레이어 수: 100

정적 생성자는 맨 처음에 한 번만 호출된 것을 확인할 수 있습니다.

주의 사항
정적 생성자 안에서 너무 무거운 작업이나, 실패 가능성이 큰 작업을 수행하는 것은
프로그램 시작 시 느려지거나, 타입 전체가 사용 불가능해질 수 있습니다.
이러한 이유로, 정적 생성자는 가볍고, 실패하지 않는 작업에서 사용해야 합니다.

2)정적 클래스(Static Class)

정적 클래스는 모든 멤버가 static으로만 이루어진 클래스를 말합니다.
이렇게 하면 "이 클래스는 순수한 기능 모음집입니다."라는 의도를
코드에 명확하게 표현할 수 있습니다.

[특징]
1. static키워드를 클래스 선언에 붙여야 합니다.
2. 오직 정적 멤버(필드, 메서드 등)만 가질 수 있습니다.
3. 인스턴스를 생성할 수 없습니다. (new키워드 사용 불가)
4. 정적 생성자를 제외한 생성자를 가질 수 없습니다.
5. 다른 클래스를 상속받거나, 다른 클래스에게 상속을 해줄 수 없습니다.

비유: 공용 도구함

유용한 기능(메서드)이나 상수(const)들을 모아놓은 공용 도구 상자입니다.
물건 자체를 새로 만들(new) 필요 없고, 누구나 사용할 수 있어요.

[코드]

using System;

// static 키워드가 붙은 정적 클래스
public static class GameHelper
{
    public const float Pi = 3.14159f;

    // 두 점 사이의 거리를 계산하는 정적 메서드
    public static double GetDistance(double x1, double y1, double x2, double y2)
    {
        double dx = x2 - x1;
        double dy = y2 - y1;
        return Math.Sqrt(dx * dx + dy * dy);
    }

    // 주사위를 굴리는 정적 메서드
    public static int RollDice()
    {
        Random random = new Random();
        return random.Next(1, 7); // 1부터 6까지의 정수 중 하나를 반환
    }
}

class Program
{
    static void Main()
    {
        Console.WriteLine("=== 게임 계산을 위한 공용 도구함 ===");

        // 정적 클래스는 인스턴스화할 수 없습니다.
        // GameHelper helper = new GameHelper(); // 컴파일 오류!

        // 클래스 이름으로 직접 메서드 호출
        double distance = GameHelper.GetDistance(0, 0, 3, 4);
        Console.WriteLine($"두 점 (0,0)과 (3,4) 사이의 거리는? {distance}");

        int diceValue = GameHelper.RollDice();
        Console.WriteLine($"주사위를 굴려 나온 숫자는? {diceValue}");
    }
}

[실행 결과]

=== 게임 계산을 위한 공용 도구함 ===
두 점 (0,0)과 (3,4) 사이의 거리는? 5
주사위를 굴려 나온 숫자는? 3

정적 클래스는 유틸리티 메서드 모음이나 상수 정의처럼
상태를 저장하지 않거나, 전역적으로 공유해도 되는 값에 잘 어울립니다.
반대로, 게임 진행 상태나 사용자 상태처럼 자주 변하는 데이터를
정적 필드에 넣어 두면 테스트와 유지보수가 힘들어질 수 있습니다.

3)요약

구분정적 생성자정적 클래스
역할클래스의 정적 멤버를 초기화하는 특별한 메서드정적 멤버들만 모아놓은 특별한 클래스
선언static ClassName() { ... }public static class ClassName { ... }
호출CLR에 의해 자동으로 단 한 번만 호출개발자가 필요할 때마다 직접 클래스이름.멤버로 호출
제약접근 제한자, 매개변수 사용 불가모든 멤버가 static이어야 함, new로 객체 생성 불가
profile
🚀 미래의 엔지니어를 꿈꾸는 훈련생의 기록 📝

0개의 댓글