본문 바로가기
Language/CPP&C#

[C#] Null

by nyangzzi 2021. 5. 18.
반응형
Nullable

 

일반적인 변수의 경우, 값이 비어 있을 수 없다. 프로그램에 치명적인 오류를 불러일으킬 수 있기 때문이다.

int a = 3;
int b = 4;

WriteLine(a+b);	//7

위의 코드는 a와 b를 더하는 코드로, 실행시켜보면 a의 값인 3과 b의 값인 4가 더해진 7이 출력되는 것을 확인 할 수 있다.

 

하지만 만약 a에 값이 비어있다면?

없는 값에 4를 더할 수는 없다. a는 0이 아니라 정말 '없는 값' 이기 때문이다. 이렇게 아무런 값이 없는 것은 null 상태라고 한다.

비어있는 값을 연산하려고 시도하면 프로그램은 큰 오류를 불러올 수 있기 때문에, 기본적으로 변수는 null 값을 넣을 수 없도록 선언된다.

 

하지만 프로그래밍을 하다보면 변수에 값을 넣어주고 싶지 않을 때가 있다.

이때 Nullable 형식을 사용하여 변수에 특정 값이 아닌 NULL, 즉 비어있는 변수를 만들 수 있다.

 

Nullalble이란, 말 그대로 Null(비어 있는) + able(가능한) 의 합성어로 "비어있는 것이 가능한 상태"라는 뜻이다. 

이를 선언하기 위해서는 다음과 같이 원래의 데이터 형식 이름 뒤에 '?'만 붙여주면 된다.

//데이터형식? 변수명;

int? a= null;

 

이것이 바로 a를 비어있는 값으로 설정해준 것이다.

이때, a는 선언과 동시에 초기화 해주어야한다. a가 현재 NULL값을 가지는 것인지, 특정한 값을 가지는 것인지 컴파일러에게 알려주어야하기 때문이다. 다음처럼 a를 사용 할 때만 값을 넣어주고, 다시 비어있는 값으로 초기화 해주는 것도 가능하다.

 

int? a = null;
int b = 4;
a = 3;
WriteLine(a+b); //7
a = null;

위의 코드를 실행시켜보면 첫번 째 코드와 동일하게 7를 출력하는 것을 알 수 있다.

 

하지만 이렇게 null 값을 넣을 수 있도록 선언해주었다고 해서 null을 가지고 있는 a를 b와 더해줄 수 있는 것은 아니다. 오히려 프로그래머가 오류가 발생 할 수 있도록 허용해준 것이나 다름없다. 따라서 위험을 방지하기 위해 a를 사용하기 전, 현재 a에 null값이 있는지 확인해주어야한다. 그리고 이를 확인할 수 있도록 해주는 것이 바로 HasValue 속성이다.

 


 

HasValue와 Value

 

HasValue는 해당 변수가 값을 가지고 있는지 그렇지 않은 지에 대한 속성이다.

변수가 값을 가지고 있다면 True를, 가지고 있지 않다면 False를 반환한다.

 

Value는 변수에 담겨있는 값 자체를 나타낸다.

만약 변수가 값을 가지고 있지 않은데 Value를 이용하여 값을 출력하려고 시도하면, CLR은 InvalidOperation Exception 예외를 띄운다.

하지만 값을 가지고 있다면, 해당 값을 가지고 온다.

int? a = null;

if (a.HasValue == false)
{
	WriteLine("a의 HasValue: " + a.HasValue ); //False
	WriteLine("a에 값을 입력하세요.");
}
else
{
	WriteLine("a의 HasValue: " + a.HasValue);	//True
	WriteLine("a의 값: " + a.Value);
}

 

위의 코드는 a의 값이 null인지 확인한 뒤,

null이라면 False를, null이 아니라면 a의 값을 출력하는 프로그램이다.

 

현재는 a의 값이 null이므로, 실행결과는 다음과 같다.

 

만약 a에 특정한 값을 넣어주면, 다음과 같은 실행결과를 반환한다.

int? a = null;
a = 3;

 


 

null 조건부 연산자

 

하지만 개발자가 이렇게 일일히 NULL을 체크해야하는 것은, 여전히 프로그램에 큰 오류를 불러일으킬 수 있다. 사람은 누구나 실수를 할 수 있기 때문이며 특히 클래스와 같이 프로그램의 구조가 복잡해지면 매번 null 체크를 해주는 것은 개발에 있어 많은 번거로움이 발생한다. 이를 방지하기 위하여, C# 6.0부터 널 조건부 연산자가 도입되었으며 다음과 같은 기호를 사용하여 표현 할 수 있다.

 

?.

?. 가 하는 역할은 객체의 멤버에 접근하기 전에 해당 객체가 null인지 검사하여 그 결과가 참(객체가 null)이라면 결과로 null을 반환하고, 거짓이라면 해당 객체의 멤버를 반환한다.

class Student
{
	public int number;
}

Class Program
{
	static void Main(String[] args)
	{
		Student member = null;
		int? code = member?.number;	//member 객체가 null이 아니면 number에 접근하게 해줌
		WriteLine("code : " + code);
        
        WriteLine("==================");
        
        Student member2 = new Student();
		member2.number = 5;
		int? code2 = member2?.number;	//member 객체가 null이 아니므로 number에 접근 가능
		WriteLine("code2 : " + code2);
			
	}
}

위의 코드에서

첫 번째 객체 member은 null이므로, member?. 역시  null을 반환한다. 따라서 code 또한 null므로

code : 

만 출력하고 뒤에 아무것도 출력되지 않는다.

 

두 번째 객체 member2는 null이 아니므로 member2?. 는 number에 접근하는 것을 허용한다. 따라서 member2.number의 값을 가지고 와 code2에 넣는 것이 가능하며, 

code2 : 5

를 출력하게 된다.

 

 

?[]

?[] 도 ?. 와 유사한 기능을 한다. 차이는 객체의 멤버 접근이 아닌 배열과 같은 컬렉션 객체의 첨자를 이용한 참조에 사용된다는 점이다.

using System;
using static System.Console;
using System.Collections;

namespace nullPractice
{
	class Program
	{
		static void Main(String[] args)
		{
			ArrayList food = null;	//null
			food?.Add("치킨");	//food?.가 null을 반환하므로 Add()는 호출되지 않음
			food?.Add("쌀국수");
			WriteLine($"Menu : {food?.Count}");
			WriteLine($"{food?[0]}");
			WriteLine($"{food?[1]}");

			WriteLine("==================");

			ArrayList movie = new ArrayList(); //null이 아닌 리스트
			movie?.Add("어벤져스");    
			movie?.Add("미니언즈");
			WriteLine($"Table : {movie?.Count}");
			WriteLine($"{movie?[0]}");
			WriteLine($"{movie?[1]}");


		}

	}
}

 


null 병합 연산자

 

null 병합 연산자 역시 변수와 객체의 null 검사를 간결하게 만들어주는 역할을 하며, 다음과 같이 쓴다.

??

?? 연산자는 두 개의 피연산자 중 왼쪽 피연산자가 null인지 판단하여, null이 아니면 왼쪽 피연산자의 값을, null이면 오른쪽 피연산자를 반환한다.

 

int? a = null;
WriteLine("a :" + $"{a ?? 0}");

int? b = 99;
WriteLine("b :" + $"{b ?? 0}");

위의 코드에서 a는 null이므로 0을 반환하지만, b는 null이 아니므로 99를 반환하는 것을 알 수 있다.

반응형

'Language > CPP&C#' 카테고리의 다른 글

[C#] var 키워드  (0) 2021.05.20
[C#] object (boxing/unboxing)  (0) 2021.05.20
[C#] CLR(Common Language Runtime)  (0) 2021.05.18
[Visual Studio] 명령 프롬프트(cmd)로 파일 실행하기  (0) 2021.05.18
[C++] Hello, World!  (0) 2021.05.14

댓글