C#에서는 AS, IS 연산자가 존재한다. 형변환을 위해서 탄생한 예약어인데 알아두면 유용한 연산자이며, 타인이 작성한 코드를 무리없이 읽기 위해서도 필히 숙지해야할 연산자 중 하나이다. 본포스팅에서는 AS 연산자와 IS 연산자에 대해서 알아보도록 한다.

 

 

# AS, IS 연산자의 개념

기본적으로 제공되는 int, bool, string과 같은 타입 외에도, 클래스간 캐스팅 작업이 필요한 경우가 있다. 예를들어 상속관계에 있는 두 클래스에서 자식 클래스는 부모 클래스에 대입될 수 있지만, 부모 클래스는 자식 클래스에 대입될 경우 아래와 같이 오류가 발생한다.

 

"암시적으로 'ConsoleApp1.Program.Wookoa' 형식을 'ConsoleApp1.Program.WookoaTistory' 형식으로 변환할 수 없습니다.명시적 변환이 있습니다. 캐스트가 있는지 확인하세요."

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;
 
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Wookoa wookoa = new Wookoa();
            WookoaTistory tistory = new WookoaTistory();
 
            tistory = wookoa; //오류 발생
        }
 
        class Wookoa
        {
            string _name = "Wookoa";
 
            public void NamePrint()
            {
                Console.WriteLine(_name);
            }
        }
 
        class WookoaTistory : Wookoa
        {
            String _title = "Wookoa:Tistory";
 
            public void TitlePrint()
            {
                Console.WriteLine(_title);
            }
        }
    }
}
w


 

위의 소스를 간략히 설명하자면, Wookoa 클래스를 상속받아서 WookoaTistory 클래스를 정의했다. Main 클래스에서는 부모 클래스인 wookoa 인스턴스를 자식 클래스인 tistory 인스턴스에 대입을 시도했다. 오류가 발생하는 것은 당연하다. WookoaTistory 클래스는 Wookoa 클래스를 상속받아서 필드 및 메서드를 추가로 정의했다. 반대로 말하면 Wookoa 클래스를 대입할 경우 WookoaTistory 클래스에서 추가로 정의한 필드 및 메서드는 어떻게 정의된단 말인가? 이와같이 논리적인 오류가 발생한다.

 

이런 상황에서 오류를 회피하기 위해서는 아래와 같이 명시적으로 케스팅 연산자를 활용하면 된다. 그럼에도 불구하고 컴파일 단계에서 오류를 뱉어낸다.

 

"System.InvalidCastException: ''Wookoa' 형식 개체를 'WookoaTistory' 형식으로 캐스팅할 수 없습니다.'"

 

1
2
3
4
5
6
7
8
9
...
        static void Main(string[] args)
        {
            Wookoa wookoa = new Wookoa();
            WookoaTistory tistory = new WookoaTistory();
 
            tistory = (WookoaTistory)wookoa;
        }
...
w

 

 

 

 

 

# AS, IS 연산자의 필요성

위의 글까지 이해했다면 불쾌할 수 있다. 어차피 오류를 뱉어낸다면 케스팅 연산자를 사용할 수 없도록 막으면 될 일 아닌가? 아래의 예와 같이 개발자에 의해서 의도적으로 케스팅되는 경우를 소개한다. 결론부터 말하자면 부모 클래스를 자식 클래스에 대입하는 경우가 발생하고, 그러한 행위를 도와주는 것이 AS, IS 연산자다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
 
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Wookoa wookoa = new Wookoa();
            WookoaTistory tistory = new WookoaTistory();
            WookoaTistory tistory2 = new WookoaTistory();
 
            wookoa = tistory;
            tistory2 = (WookoaTistory)wookoa;
        }
 
        class Wookoa
        {
            string _name = "Wookoa";
 
            public void NamePrint()
            {
                Console.WriteLine(_name);
            }
        }
 
        class WookoaTistory : Wookoa
        {
            String _title = "Wookoa:Tistory";
 
            public void TitlePrint()
            {
                Console.WriteLine(_title);
            }
        }
    }
}
w

 

 

위의 소스를 설명하자면, 기존의 소스에서 달라진 점은 자식 클래스를 부모 클래스에 대입한 뒤, 다시 부모 클래스를 자식 클래스에 대입한다는 점이다. 이때 사용한 것이 케스팅 연산자 (WookoaTistory)를 사용했다. 위의 소스는 문제없이 작동한다.

 

클래스는 참조형 변수 타입이기 때문에 주소값을 저장한다는 사실을 기반으로 위 소스를 다시 살펴보자. 먼저, 자식 클래스의 주소값을 부모 클래스에 저장한다. 여기서 문제될 것은 없다. 두번째로 부모 클래스의 값을 명시적으로 형변환 해서 제 2의 자식 클래스에 저장한다. 여기서 부모 클래스에 저장된 주소 값은 원래 자식 클래스를 가리키던 주소값이기 때문에 컴파일 단계에서도 오류를 뱉어내지 않는다.

 

단지 wookoa, tistory, tistory2 인스턴스들은 주소값만 주고 받은것이고 실제로 컴파일할 때 tistory2의 메모리 공간에는 tistory 인스턴스를 가리키는 주소값이 저장되어 있을 것 이다. 만약, tistory2 인스턴스가 최종적으로 가리키는 주소 값이 wookoa 인스턴스와 같이 부모 클래스인 경우에는 오류를 뱉어내겠지만 말이다.

 

 

 

 

# AS, IS 연산자의 활용

처음에는 조금 억지스러울 수 있겠지만 위의 상황과 같이 부모 클래스를 자식 클래스에 대입하는 경우에 자칫하다가 오류를 발생시킬 수 있다. 오류를 발생시키는 것인 닷넷 환경에서 내부적으로 큰 부하가 발생한다. 그렇기 때문에 오류를 발생시키지 않고로 형변환이 가능한지 여부를 체크하기 위한 기능이 필요했다. 그로인해 AS, IS 연산자가 탄생하게 되었다.

 

-. AS 연산자

형변환이 가능하면 형변환을 수행하고, 그렇지 않으면 null 값을 대입하는 연산자다. 아래와 같이 형변환이 가능한지 여부를 체크해서 프로그램을 분기시킬 수 있다. 따라서, 형변환이 가능한 경우에만 케스팅 연산자로 대입시킬 수 있게된다. 참고로 AS 연산자는 참조형 변수에 대해서만 적용할 수 있으며, 참조형 타입으로만 체크가 가능하다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
 
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Wookoa wookoa = new Wookoa();
            WookoaTistory tistory = new WookoaTistory();
 
            tistory = wookoa as WookoaTistory;
            
            if (tistory == null)
                Console.WriteLine("형변환 불가능!");
            else
                Console.WriteLine("형변환 가능!");
        }
 
        class Wookoa
        {
            string _name = "Wookoa";
 
            public void NamePrint()
            {
                Console.WriteLine(_name);
            }
        }
 
        class WookoaTistory : Wookoa
        {
            String _title = "Wookoa:Tistory";
 
            public void TitlePrint()
            {
                Console.WriteLine(_title);
            }
        }
    }
}
w

 

 

-. IS 연산자

형변환이 가능한 여부를 불린형으로 결과값을 반환한다. AS 연산자와 IS 연산자의 사용 기준은 명확하다. 형변환된 인스턴스가 필요하면 AS 연산자, 그렇지 않으면 IS 연산자를 사용하면 된다. MSDN에 따르면 IS 연산자는 C# 7.0부터 지원하며, 대부분 시나리오에서는 AS 연산자보다 IS 연산자를 먼저 사용해서 객체의 값을 할당하는 것이 더 적합하다고 한다. 아래의 소스와 같이 캐스팅 여부를 먼저 판단한 뒤, 가능할 경우에만 인스턴스를 생성할 수 있기 때문이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
 
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Wookoa wookoa = new Wookoa();
                        
            if (wookoa is WookoaTistory)
            {
                Console.WriteLine("형변환 불가능!");
            }
            else
            {
                Console.WriteLine("형변환 가능!");
                WookoaTistory tistory = (WookoaTistory)wookoa;
            }
        }
 
        class Wookoa
        {
            string _name = "Wookoa";
 
            public void NamePrint()
            {
                Console.WriteLine(_name);
            }
        }
 
        class WookoaTistory : Wookoa
        {
            String _title = "Wookoa:Tistory";
 
            public void TitlePrint()
            {
                Console.WriteLine(_title);
            }
        }
    }
}
w

 

 

위와같이 AS 연산자와 IS 연산자의 필요성과 차이점에 대해서 알아봤다. 본인이 숙지한 개념에 대해서 주절주절 적어내려 봤다. 개념을 이해하는데 조금이나마 도움이 되길 바라는 마음이며, 오탈자나 잘못된 부분이 있으면 지적도 감사히 받겠다. 본 포스팅은 여기서 마무리 짓도록 한다.

 

 

Private comment