30. 정적 생성자와 타입 초기화 타이밍(beforefieldinit)

난이도 중 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// 주제: 정적 생성자(static constructor)와 타입 초기화 타이밍, beforefieldinit
//
// 과제:
//  1) 아래 프로그램의 출력을 순서까지 예측하라.
//  2) 명시적 정적 생성자가 있는 타입과 없는 타입(필드 이니셜라이저만)의 초기화 시점이
//     어떻게 다른지(beforefieldinit 플래그), "정확히 언제" 타입 초기화가 트리거되는지 설명하라.
//  3) 마지막 두 줄(Mutual.A / Mutual.B)에서 순환 정적 초기화가 어떤 값을 관측하게 되는지 설명하라.
//     (내부 동작 설명은 answer.md 에)

using System;

public static class Program
{
    public static void Main()
    {
        Console.WriteLine("start");
        Console.WriteLine(Config.Value);      // beforefieldinit 후보 타입
        Console.WriteLine(Counter.Next());    // 명시적 static ctor 보유
        Console.WriteLine(Counter.Next());

        Console.WriteLine("--- mutual ---");
        Console.WriteLine(Mutual.A);          // 먼저 접근되는 쪽
        Console.WriteLine(Mutual.B);
    }
}

public static class Config
{
    public static readonly int Value = Load();
    private static int Load() { Console.WriteLine("Config.Load"); return 42; }
}

public static class Counter
{
    private static int _n;
    static Counter() { Console.WriteLine("Counter..cctor"); _n = 100; }
    public static int Next() => ++_n;
}

// 순환 정적 초기화: A 초기화가 B 를, B 초기화가 A 를 참조한다.
public static class Mutual
{
    public static readonly int A = ComputeA();
    public static readonly int B = 10;
    private static int ComputeA() => Mutual2.Bv + 1;
}
public static class Mutual2
{
    public static readonly int Bv = ComputeB();
    public static readonly int Av = 5;
    private static int ComputeB() => Mutual.B + 1;   // 이 시점 Mutual.B 값에 주의
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.