23. [Flags] enum 의 내부 표현과 Enum.HasFlag 의 박싱 비용

난이도 중 해설 보기 →

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

결함 코드 · C#
// 주제: [Flags] enum 의 내부 표현(정수 기반 값 타입)과, Enum.HasFlag 가 내부적으로
//       무엇을 하는지 — 왜 비트 AND 연산자 대신 쓰면 성능 함정이 되는가.
//
// 게임서버에서 흔한 패턴: 엔티티/세션의 상태를 [Flags] enum 비트마스크로 표현하고
// (예: 마비/은신/무적 등 버프 상태), 매 틱마다 수만 개 엔티티에 대해 상태를 검사한다.
//
// 다음을 예측·설명하라:
//  (1) StatusFlags 는 값 타입(struct 계열)인 enum 인데, HasFlag(StatusFlags) 는
//      매개변수 타입이 Enum(추상 기반 클래스)이다. 호출부에서 (A) 지점마다 어떤 변환이
//      일어나는가? 그 변환은 힙 할당을 유발하는가?
//  (2) (B) 의 비트 AND 방식과 (A)의 HasFlag 방식은 같은 결과를 내는가? 성능 특성이
//      왜 다른가? (박싱 여부, 가상 호출 여부)
//  (3) enum 의 밑바탕 타입(underlying type)은 기본이 무엇이고, 이를 바꾸면(byte 등)
//      메모리 사용량/비교 연산에 어떤 영향이 있는가?
//  (4) 매 틱 수만 번 호출되는 핫 패스에서 (A) 방식을 쓰면 GC 에 어떤 부담을 주는지,
//      그리고 왜 릴리스 빌드에서도 이 오버헤드가 사라지지 않는지 설명하라.

using System;

[Flags]
public enum StatusFlags
{
    None      = 0,
    Stunned   = 1 << 0,
    Silenced  = 1 << 1,
    Invisible = 1 << 2,
    Invincible= 1 << 3,
}

public static class StatusChecker
{
    public static bool IsStunnedViaHasFlag(StatusFlags status)
    {
        // (A) HasFlag 의 매개변수는 Enum 타입 — status 는 여기로 어떻게 전달되는가?
        return status.HasFlag(StatusFlags.Stunned);
    }

    public static bool IsStunnedViaBitwise(StatusFlags status)
    {
        // (B) 순수 비트 연산 — 힙 할당 없이 정수 AND 로 끝난다
        return (status & StatusFlags.Stunned) == StatusFlags.Stunned;
    }

    // 매 틱마다 수만 개 엔티티를 검사하는 핫 패스를 흉내
    public static int CountStunned(StatusFlags[] allEntities, bool useHasFlag)
    {
        int count = 0;
        foreach (var s in allEntities)
        {
            bool stunned = useHasFlag ? IsStunnedViaHasFlag(s) : IsStunnedViaBitwise(s);
            if (stunned) count++;
        }
        return count;
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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