본문 바로가기
C#

C#의 is 와 as 키워드 (#02)

by Oz Driver 2025. 6. 26.

1편에서는 is 와 as 에 대한 기본적인 코드를 가지고 살펴보았습니다. 

이번 편에서는 보다 실용적인 예제를 다뤄보겠습니다.

 

예시 클래스

class Enemy
{
    public virtual void Cry()
    {
        Console.WriteLine("Enemy 가 괴성을 지릅니다");
    }
}

class Zombie : Enemy
{
    public override void Cry()
    {
        Console.WriteLine("Zombie : 으어어어...");
    }
}

class Robot : Enemy
{
    public override void Cry()
    {
        Console.WriteLine("Robot: 삐비빅! 시스템 경고!");
    }
    
    public void Transform()
    {
        Console.WriteLine("Robot: 변신합니다!");
    }
}

 

is로 타입 확인 + 변수 선언 + 함수 호출

void HandleEnemy(Enemy enemy)
{
    // 1단계 : 타입이 Zombie인지 확인
    if (enemy is Zombie)
    {
        // 2단계 : 변수 선언 (캐스팅 필요)
        Zombie zombie = (Zombie)enemy;

        // 3단계 : 해당 클래스의 함수 호출
        zombie.Cry();
    }

    // 또 다른 타입 확인도 마찬가지 방식
    else if (enemy is Robot)
    {
        Robot robot = (Robot)enemy;
        robot.Cry();
    }
    
    else
    {
        enemy.Cry();
    }
}

 

패턴 매칭(pattern matching)

C# 7.0부터는 타입을 확인하면서 동시에 사용할 수 있는 변수를 선언할 수 있습니다.  
공식 문서에서는 이를 "패턴 매칭(pattern matching)"이라고 부르지만, 쉽게 말하면 "is로 타입을 확인하고 변수까지 한 번에 선언하는 방식" 입니다.

위 코드를 적용해보면 다음과 같습니다.

void HandleEnemy(Enemy enemy)
{
    if (enemy is Zombie zombie)
    {
        zombie.Cry();
    }
    else if (enemy is Robot robot)
    {
        robot.Cry();
    }
    else
    {
        enemy.Cry();
    }
}

 

여기서 만약 enemy 가 null 이라면 어떻게 처리가 될까요?

Enemy enemy = null;

if (enemy is Zombie zombie)
{
    zombie.Cry(); // ❌ 실행 안 됨
}
else
{
    // 여기가 실행됨
    Console.WriteLine("enemy가 null이거나 Zombie 타입이 아님"); 
}

 

is 는 내부적으로 null 체크도 같이 해줍니다.
다시 말해, 위 코드는 사실상 아래와 같이 동작하게 됩니다.

if (enemy != null && enemy is Zombie)
{
    Zombie zombie = (Zombie)enemy;
    ...
}

 

만약 강제 형변환을 시도 했다면,

Enemy enemy = null;

// 강제 캐스팅은 null일 경우 바로 예외 발생
// NullReferenceException 또는 InvalidCastException
Zombie zombie = (Zombie)enemy;

 

이 코드를 조금 더 간결하게 수정한다면,

List<Enemy> enemies = new List<Enemy>
{
    new Zombie(),
    new Robot(),
    new Enemy()
};


foreach (Enemy enemy in enemies)
{
    enemy.Cry();

    // Robot 에게만 추가 동작 실행
    if (enemy is Robot robot)
    {
        robot.Transform(); // Robot 만 가지고 있는 고유 동작
    }
}

 

마무리

is 는 단순한 타입 검사 이상의 역할을 합니다.

null 안전성과 타입 캐스팅을 동시에 처리할 수 있기 때문에, 형변환이 필요한 상황에서 먼저 is 로 타입 검사 후에 instance 를 처리하면 훨씬 안정적이고 예외 위험도 크게 줄어듭니다.