Section 38.6: Nullable<T> 인자의 기반 (underlying) 타입에 대한 효과적인 사용법

모든 nullable 타입은 generic 타입이다. 또한 모든 nullable 타입은 값 (value) 타입이다.

역주: C# 8.0부터는 nullable reference 타입에 대한 새로운 개념이 추가되었습니다. Microsoft 문서 를 참조하세요.

Reflection 이나 코드 자동생성 목적의 코드를 작성할 때, Nullable.GetUnderlyingType 메소드의 결과를 효과적으로 사용할 수 있는 몇가지 기법을 아래의 코드에서 소개하고 있다:

public static class TypesHelper { public static bool IsNullable(this Type type) { Type underlyingType; return IsNullable(type, out underlyingType); } public static bool IsNullable(this Type type, out Type underlyingType) { underlyingType = Nullable.GetUnderlyingType(type); return underlyingType != null; } public static Type GetNullable(Type type) { Type underlyingType; return IsNullable(type, out underlyingType) ? type : NullableTypesCache.Get(type); } public static bool IsExactOrNullable(this Type type, Func < Type, bool > predicate) { Type underlyingType; if (IsNullable(type, out underlyingType)) return IsExactOrNullable(underlyingType, predicate); return predicate(type); } public static bool IsExactOrNullable < T > (this Type type) where T: struct { return IsExactOrNullable(type, t => Equals(t, typeof (T))); } }

사용 예제:

Type type = typeof (int).GetNullable(); Console.WriteLine(type.ToString()); if (type.IsNullable()) Console.WriteLine("Type is nullable."); Type underlyingType; if (type.IsNullable(out underlyingType)) Console.WriteLine("The underlying type is " + underlyingType.Name + "."); if (type.IsExactOrNullable < int > ()) Console.WriteLine("Type is either exact or nullable Int32."); if (!type.IsExactOrNullable(t => t.IsEnum)) Console.WriteLine("Type is neither exact nor nullable enum.");

출력 결과:

System.Nullable`1[System.Int32] Type is nullable. The underlying type is Int32. Type is either exact or nullable Int32. Type is neither exact nor nullable enum.

참고로, NullableTypesCache 는 아래와 같이 선언되어 있다:

static class NullableTypesCache { readonly static ConcurrentDictionary < Type, Type > cache = new ConcurrentDictionary < Type, Type > (); static NullableTypesCache() { cache.TryAdd(typeof (byte), typeof (Nullable < byte > )); cache.TryAdd(typeof (short), typeof (Nullable < short > )); cache.TryAdd(typeof (int), typeof (Nullable < int > )); cache.TryAdd(typeof (long), typeof (Nullable < long > )); cache.TryAdd(typeof (float), typeof (Nullable < float > )); cache.TryAdd(typeof (double), typeof (Nullable < double > )); cache.TryAdd(typeof (decimal), typeof (Nullable < decimal > )); cache.TryAdd(typeof (sbyte), typeof (Nullable < sbyte > )); cache.TryAdd(typeof (ushort), typeof (Nullable < ushort > )); cache.TryAdd(typeof (uint), typeof (Nullable < uint > )); cache.TryAdd(typeof (ulong), typeof (Nullable < ulong > )); //... } readonly static Type NullableBase = typeof (Nullable < > ); internal static Type Get(Type type) { // 호출 비용이 많이 드는 MakeGenericType 메소드 호출을 지양한다 return cache.GetOrAdd(type, t => NullableBase.MakeGenericType(t)); } }
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 38.5: Nullable 타입의 기본값은 null 이다

public class NullableTypesExample { static int ? _testValue; public static void Main() { if (_testValue == null) Console.WriteLine("null"); else Console.WriteLine(_testValue.ToString()); } }

출력결과:

null
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 38.4: 기본 값을 지정하여 Nullable 타입이 가지고 있는 값 가져오기

GetValueOrDefault() 메소드를 이용하면 HasValue 속성이 false 인 경우에도 값을 반환받을 수 있다 (Value 속성값 접근은 이러한 경우 예외를 발생시킨다는 차이점이 있다).

class Program { static void Main() { int ? nullableExample = null; int result = nullableExample.GetValueOrDefault(); Console.WriteLine(result); // int 에 대한 기본값인 0 을 출력할 것이다 int secondResult = nullableExample.GetValueOrDefault(1); Console.WriteLine(secondResult); // 기술된 기본값인 1 을 출력할 것이다 int thirdResult = nullableExample ?? 1; Console.WriteLine(thirdResult); // GetValueOrDefault 와 동일하지만 조금 더 간결하다 } }

출력결과:

0 1 1
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 38.3: Nullable 타입이 가지고 있는 값 얻어오기

아래와 같은 Nullable 변수가 있다고 가정할 때,

int? i = 10;

만약 해당 변수의 값을 얻어올 때 값이 null 일 경우에 대한 기본값을 지정하고 싶다면, Null 병합 (coalescing) 연산자나 GetValueOrDefault 메소드를 이용하여 기본 값을 지정하거나, 아니면 값 할당 전에 HasValue 값을 확인하는 방법을 사용할 수 있다.

int j = i ?? 0; int j = i.GetValueOrDefault(0); int j = i.HasValue ? i.Value : 0;

아래에 소개된 코드와 같은 사용 예제는 언제나 안전하지 않다. 만약 실행 시점에 i 의 값이 null 이라면, System.InvalidOperationException 예외가 발생할 것이다. 컴파일 시점에 값이 설정되지 않았음이 감지된다면, Use of unassigned local variable 'i' 에러가 발생할 것이다.

int j = i.Value;
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 38.2: Nullable 타입 변수가 값을 가지고 있는지 확인하기

int? i = null; if (i != null) { Console.WriteLine("i is not null"); } else { Console.WriteLine("i is null"); }

아래 예제 역시 동일하게 동작한다:

if (i.HasValue) { Console.WriteLine("i is not null"); } else { Console.WriteLine("i is null"); }
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 38.1: Nullable 타입 변수 초기화하기

null 값을 가지는 경우:

Nullable<int> i = null;

혹은:

int? i = null;

혹은:

var i = (int?)null;

null 이 아닌 값을 가지는 경우:

Nullable<int> i = 0;

혹은:

int? i = 0;

역주: 원문에는 빠져있지만 위 null 값을 갖는 예제와 마찬가지로 아래 코드도 동일하게 동작합니다.
var i = (int?)0;

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 37.8: 명시적 숫자 (numeric) 변환

명시적 타입 변환 연산자를 활용하면 숫자 (numeric) 타입들간의 변환을 수행할 수 있으며, 이는 해당 타입들이 서로 확장 (extend) 이나 구현 (implement) 관계에 있지 않다 하더라도 무방하다.

double value = -1.1; int number = (int) value;

여기서 유의할 점은, 만약 변환의 최종 대상이 되는 타입이 기존 타입에 비해 낮은 정확도 (precision) 를 가지고 있을 경우, 기존 값이 가지고 있던 정확도는 유실된다는 것이다. 예를 들어, double 타입인 -1.1 값을 위 예제와 같이 변환할 경우 최종 정수값은 -1 이 될 것이다.

또한, 숫자 타입 변환은 컴파일 시점의 타입에 의존적으로 이루어지므로, 객체로 박싱 (boxing) 된 경우에는 정상 동작하지 않는다.

object value = -1.1; int number = (int) value; // InvalidCastException 을 발생시킨다
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 37.7: 묵시적 타입 변환 (Implicit Casting)

만약 컴파일러가 어떤 값에 대해, 해당 값이 항상 변환 가능한 타입이 있음을 알고 있다면, 필요한 경우 그 타입으로의 자동 변환을 적절히 수행해 줄 수 있다.

int number = -1; object value = number; Console.WriteLine(value);

이 예제에서는, 컴파일러가 모든 int 값들이 object 타입으로 변환 가능함을 알고 있기에, 흔히 사용되는 명시적 (explicit) 타입 변환 문법을 사용할 필요가 없다. 사실, object 타입을 파라미터로 받는 Console.WriteLine() 메소드에 -1 값을 별도의 변수 생성 없이 그대로 넘기는 것 역시 가능하다.

Console.WriteLine(-1);
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

+ Recent posts