6. null
변수를 선언하고 값을 할당하는 경우 해당 변수가 할당된 값을 가질 것이라는 점은 분명히 알 수 있지만 아무런 값도 할당되지 않은 상태(정수형의 경우 기본값이 0이 되는 것처럼 기본값으로 대체되는 경우도 있음)라면 이때는 null이 변수의 값을 표현할 수 있는 수단이 될 수 있습니다.
● 값 형식에서 null 사용하기
기본적으로 int나 DateTime과 같은 값 형식은 굳이 값이 할당되지 않더라도 기본값의 개념이 있어서 어떤 식으로든 항상 값이 할당된 상태라고 볼 수 있습니다. 따라서 null에 대한 대비를 따로 하지 않아도 되지만 만약 어떤 값을 읽어서 값 형식의 변수에 해당 값이 할당되는 경우 그 값이 null상태라면 어떤 식으로는 값 형식도 null상태가 될 수 있어야 합니다. 그리고 이런 상태의 값 형식 변수를 'null 가능한 값 형식'이라고 합니다.
null 가능한 값 형식은 변수의 Type뒤에 물음표(?)를 사용하여 표현합니다.
int? i = null;
Console.WriteLine(i);
//공백 -> i값은 null이므로 아무것도 표시되지 않음
● 참조 형식에서 null 사용하기
C# 8.0에서 가장 중요한 변화중 하나는 참조 타입에서도 null가능 여부를 적용할 수 있다는 것입니다. 이전에 참조 타입은 항상 null이 가능한 것이었습니다.
이것은 소스코드 파일이나 프로젝트 단위의 설정을 통해 가능한데 프로젝트에서 *. csproj파일을 열어보면 관련 설정을 확인해 볼 수 있습니다.
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
위 설정 중에서 <Nullable>enable</Nullable>이 참조 타입에서 null 가능함을 의미하는 것으로 만약 이 설정을 유지하고 아래와 같은 코드를 작성한다면
string s = null;
non-nullable 타입으로 변환할 수 없다면 오류를 보게 됩니다. 따라서 명시적으로 ?를 사용해 null 가능한 참조 타입임을 명시해야 합니다.
string? s = null;
프로젝트 단위로 non-nullable설정을 적용했다고 하더라도 특정 파일 안에서는 호환성 등을 고려해 이전 동작이 그대로 유지되어야 할 필요가 있을 수 있습니다. 그렇다면 해당 파일의 가장 상위나 기능 적용이 필요한 구문 시작 전에 아래와 같은 설정을 적용할 수 있습니다.
#nullable disable
string s = null;
#nullable enable
string? ss = null;
그리고 위와 같은 nullable은 값타입에도 ?를 사용함으로써 동일하게 적용할 수 있습니다.
● null 확인
값 타입이나 참조 타입이나 null 가능한 경우라 한다면 해당 변수를 사용하기 전 null상태 여부를 확인하는 건 필수입니다. 그렇지 않으면 경우에 따라 'NullReferenceException'예외를 일으킬 수도 있기 때문입니다.
그래서 통상 다음과 같은 방법으로 null상태를 확인할 수 있습니다.
if (car == null)
{
Console.WriteLine("c는 null입니다.");
}
더 나아가 C# 7.0에서는 '=='연산자를 대체할 수 있는 'is null'이 추가되었고
if (car is null) //또는 반대의 경우 (!(car is null))로 처리
{
Console.WriteLine("c는 null입니다.");
}
C# 9.0에 와서는 부정 적용이 가능한 'is not null'이 추가되었습니다.
if (car is not null)
{
Console.WriteLine("c는 null이 아님");
}
또는 아래와 같이 특정 Type이 null 가능한 Member를 사용하고 있는 경우
namespace mylibrary;
public class Car
{
public int? Speed { get; set; }
}
해당 Member에 접근하기 위해 '?.'을 사용할 수 있습니다.
Car car = new();
Console.WriteLine(car?.Speed);
일반적으로 점(.)을 사용했을 때 Speed가 null이라면 'NullReferenceException'예외를 발생시키질 수 있지만 '?.'으로 접근한다면 null인 경우 예외를 발생시키는 대신 null을 그대로 반환하게 됩니다.
어떤 경우는 결과가 null이라면 null대신 대체 가능한 다른 값이 할당되기를 원할 수도 있는데 그런 경우는 null 병합 연산자인 ??을 사용할 수 있습니다.
Car car = new();
int speed = car?.Speed ?? 80;
따라서 위 결과는 speed변수에 80 값을 할당하게 됩니다.
'.NET > C#' 카테고리의 다른 글
[C#] 인터페이스(Interface)와 상속(Inheriting) - 7. Code분석(StyleCop) (0) | 2022.06.24 |
---|---|
[C#] 인터페이스(Interface)와 상속(Inheriting) - 6. 상속(Inheriting) (0) | 2022.06.24 |
[C#] 인터페이스(Interface)와 상속(Inheriting) - 4. 참조타입과 값타입 (0) | 2022.06.24 |
[C#] 인터페이스(Interface)와 상속(Inheriting) - 3. 인터페이스(Interface) (0) | 2022.06.24 |
[C#] 인터페이스(Interface)와 상속(Inheriting) - 2. 제네릭(generic) (0) | 2022.06.24 |