번역/C# Notes for Professionals

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

노초코 2022. 2. 9. 13:53

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/

반응형