본문 바로가기
IT/C#(CS)

CS 기초강좌 9. 널 조건부 연산자, 널 접합 연산자 Elvis operator "?" "?[" "??"

by 신림83 2020. 11. 15.
반응형

CS 기초강좌 9. 널 조건부 연산자, 널 접합 연산자 Elvis operator "?" "?[" "??"

다음 코드를 봅시다.

using System;

class Point 
{
    public int x = 0;
    public int y = 0;

    public override string ToString()
    {
        return string.Format($"{base.ToString()} x:{x} y:{y}");
    }

    public void PrintToString()
    {
        Console.WriteLine(ToString());
    }
}

class Program
{
    public static Point CreatePoint(int x, int y)
    {
        if (x < 0 || y < 0)
            return null;

        Point pt = new Point();
        pt.x = x;
        pt.y = y;
        return pt;
    }

    static void Main(string[] args)
    {
        Point pt = CreatePoint(100, 100);
        pt.PrintToString();
    }
}

Point 라는 클래스를 만들고 필드로 x,y 를 둡니다.

그리고 PrintToString 을 호출하면 내부정보를 출력하게 만들었습니다.

 

CreatePoint 란 메소드를 호출하면 Point 객체를 생성하여 반환해줍니다.

단 조건이 있습니다. x, y 가 음수라면 null을 반환합니다.

 

실제 실행하는 Main에서 100, 100 정보를 입력하여 객체를 생성시키고, 정보를 출력해봅니다.

 

출력결과

잘 동작함을 볼수 있습니다.

이제는 객체를 생성시 음수를 사용해 보겠습니다.

    static void Main(string[] args)
    {
        Point pt = CreatePoint(-100, 100);
        pt.PrintToString();
    }

출력결과

CreatePoint 는 정상 동작을 합니다. error은 다음 pt.PrintToString()에서 발생합니다. pt 생성 시 인자가 음수가 들어가 pt의 객체는 정상 생성되지 않고 null이 반환됩니다. 실제 객체가 존재하지 않는 상태에서 내부 메서드를 호출하려 하면 애러입니다.

 

 

이런 경우는 예외처리를 미리 해둬야 하겠죠. 다음과 같은 코드를 기대해 볼 수 있습니다.

    static void Main(string[] args)
    {
        Point pt = CreatePoint(-100, 100);

        if(pt != null)
            pt.PrintToString();
    }

널 조건부 연산자(null conditional operator) ?.

if(pt != null) 라는 조건으로 pt가 null 아닐 때만, 아래 코드가 동작하도록 해두었습니다. 위와 같은 코드는 많이 사용될 것입니다. 그래서 C#에서는 널 조건부 연산자(null conditional operator) 가 존재합니다. 위의 코드는 아래로 치환될 수 있습니다.

    static void Main(string[] args)
    {
        Point pt = CreatePoint(-100, 100);

        pt?.PrintToString();
    }

if(pt != null) pt.PrintToString(); 와 Pt?.PrintToString()은 똑같은 동작을 보장합니다. 정확히 연산자는 ?. 입니다. 이와 같은 표현은 elvis operator 이라고도 불립니다.

 

조금 더 관련 알아봅시다.

pt의 x 필드의 정보를 받고 싶다고 가정합시다.

        Point pt = CreatePoint(-100, 100);
        int ptX = pt?.x;

가능할 코드일까요? 불 가능합니다. ?. 연산자가 좌변에 존재할 시 수행되지 않은 경우는 null 을 반환하게 됩니다. 값형식은 null이 될 수 없습니다. 이럴 가능성이 내포된 경우에는 해동 코드는 동작하지 않습니다.

error

해당 코드를 수정하고 싶다면 nullable 을 사용할 수 있습니다.

Point pt = CreatePoint(-100, 100);
int? ptX = pt?.x;

배열은?

배열또한 참조 타입입니다. 다음 코드를 봅시다.

int[] arr = { 1, 2, 3, 4, 5 };
int n = arr[0];

n은 배열을 0번 인자를 참조합니다. 아무 문제가 없는 코드입니다. 다음 코드를 또 볼까요?

//int[] arr = { 1, 2, 3, 4, 5 };
int[] arr = null;
int n = arr[0];

배열이 null 이었다면, 실행 시 애러가 됩니다. 배열 또한 elvis operator를 사용하여 수정해 보겠습니다.

int[] arr = null;
int? n = arr?[0];

배열에서 널 조건부 연산자 계념을 적용시에는 ?[ 연산자를 사용할 수 있습니다.

 

널 접합 연산자(null coalescing operator) ??

다음 코드를 봅시다.

    static void Main(string[] args)
    {
        Point pt = CreatePoint(-100, 100);
        if (pt == null)
        {
            pt = CreatePoint(0, 0);
        }
        pt.PrintToString();
    }

pt 가 null일 경우에는 0,0 인자를 다시 생성 요구하는 코드입니다. 무언가 잘못된 결과이면, 다시 한번 작업을 요청하는 코드인데 이런 코드 또한 C#에서는 좀 더 쉽게 표현할수 있습니다.  널 접합 연산자(null coalescing operator)를 사용해 봅시다. 아래 코드를 봅시다.

    static void Main(string[] args)
    {
        Point pt = CreatePoint(-100, 100) ?? CreatePoint(0, 0);
        pt.PrintToString();
    }

위와 아래는 동일한 코드입니다. ?? 기준으로 우변의 연산 결과가 null 일 때 좌변을 수행하게 됩니다.

    static void Main(string[] args)
    {
        Point pt = CreatePoint(-100, 100) ?? new Point();
        pt.PrintToString();
    }

메서드가 아닌 객체 자체도 문제없습니다. 우변의 코드가 수행되는 것입니다.

 

위의 기술은 값 형식에서 사용하면 편리합니다. 아래 예제 코드를 또 보아요

int? n1 = null;
int n2 = n1; //???

n2에서 n1값을 참조해야 하는데, nullable 타입이라 애매합니다. 실제 값이 들어있을 수도 있고 아닐 수도 있고, 이럴 때 위의 ?? 사용하면 편리할 수 있습니다.

int? n1 = null;
int n2 = n1 ?? 0; 

n1이 null 이라면 0을 대입하도록 작업해 보았습니다. 이런 의도의 작업이 필요할 때가 있습니다.

 

?. ?[ ?? 뭐시여..

봐주셔서 감사합니다.

반응형

댓글