28. 확장 메서드의 정적 바인딩 vs 인스턴스 메서드의 동적 디스패치

난이도 중 해설 보기 →

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

결함 코드 · C#
// ============================================================================
// [언어 내부동작 문제] C# - 확장 메서드의 정적 바인딩 vs 인스턴스 메서드의 동적 디스패치
// ----------------------------------------------------------------------------
// 주제: 확장 메서드는 "그 타입의 진짜 멤버"가 아니다. 그러면 호출할 확장 메서드를
//       컴파일러는 언제, 무엇을 기준으로 고르는가? 인스턴스 메서드와 뭐가 다른가?
//   - 게임서버에서 흔한 패턴: IPacket, ISession 같은 인터페이스에 확장 메서드로
//     편의 기능(로깅, 직렬화 헬퍼 등)을 붙이고, 구체 타입/베이스 타입/인터페이스
//     타입 변수를 섞어서 사용한다.
//
// 과제:
//   1) 아래 main 의 출력을 예측하라. 특히 Describe() 호출이 몇 번은 인스턴스 메서드로,
//      몇 번은 확장 메서드로 해석되는지, 그리고 그 기준이 "변수의 정적 타입"인지
//      "객체의 런타임 타입"인지 예측하라.
//   2) 확장 메서드 호출이 컴파일타임에 정적 메서드 호출(예: Extensions.Describe(x))로
//      치환된다는 것이 무엇을 의미하는지, 왜 확장 메서드는 오버라이드될 수 없는지
//      설명하라.
//   3) 같은 이름의 인스턴스 메서드가 나중에 타입에 추가되면(또는 인터페이스가 그
//      멤버를 갖게 되면) 기존에 그 타입을 대상으로 하던 확장 메서드 호출이 왜 조용히
//      다른 메서드를 호출하게 될 수 있는지 설명하라.
//   (먼저 직접 예측·설명을 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System;

namespace ExtMethodBinding
{
    public interface ISession
    {
        int Id { get; }
    }

    public class BaseSession : ISession
    {
        public int Id { get; set; }
    }

    // Id 만 있고 Describe() 라는 이름의 "진짜 멤버"는 없음
    public class PlayerSession : BaseSession
    {
        // (A) 여기 주목: PlayerSession 이 스스로 Describe() 를 정의한다
        public string Describe() => $"PlayerSession(인스턴스 메서드) Id={Id}";
    }

    public static class SessionExtensions
    {
        public static string Describe(this ISession s) =>
            $"ISession 확장 메서드 Id={s.Id}";

        public static string Describe(this BaseSession s) =>
            $"BaseSession 확장 메서드 Id={s.Id}";
    }

    public static class Program
    {
        public static void Main()
        {
            PlayerSession player = new PlayerSession { Id = 1 };
            BaseSession asBase = player;
            ISession asInterface = player;

            // (B) 정적 타입이 각각 PlayerSession / BaseSession / ISession 인 세 변수가
            //     모두 같은 런타임 객체를 가리킨다.
            Console.WriteLine(player.Describe());
            Console.WriteLine(asBase.Describe());
            Console.WriteLine(asInterface.Describe());
        }
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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