Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
65
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

Chapter 38: Nullable types

Section 38.1: Initialising a nullable

For null values:

Nullable<int> i = null;

Or:

int? i = null;

Or:

var i = (int?)null;

For non-null values:

Nullable<int> i = 0;

Or:

int? i = 0;

Section 38.2: Check if a Nullable has a value

int? i = null;

if (i != null)

{

Console.WriteLine("i is not null");

}

else

{

Console.WriteLine("i is null");

}

Which is the same as:

if (i.HasValue)

{

Console.WriteLine("i is not null");

}

else

{

Console.WriteLine("i is null");

}

Section 38.3: Get the value of a nullable type

Given following nullable int

int? i = 10;

GoalKicker.com – C# Notes for Professionals

149

In case default value is needed, you can assign one using null coalescing operator, GetValueOrDefault method or check if nullable int HasValue before assignment.

int j = i ?? 0;

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

The following usage is always unsafe. If i is null at runtime, a System.InvalidOperationException will be thrown. At design time, if a value is not set, you'll get a Use of unassigned local variable 'i' error.

int j = i.Value;

Section 38.4: Getting a default value from a nullable

The .GetValueOrDefault() method returns a value even if the .HasValue property is false (unlike the Value

property, which throws an exception).

class Program

{

static void Main()

{

int? nullableExample = null;

int result = nullableExample.GetValueOrDefault(); Console.WriteLine(result); // will output the default value for int - 0 int secondResult = nullableExample.GetValueOrDefault(1); Console.WriteLine(secondResult) // will output our specified default - 1 int thirdResult = nullableExample ?? 1;

Console.WriteLine(secondResult) // same as the GetValueOrDefault but a bit shorter

}

}

Output:

0

1

Section 38.5: Default value of nullable types is null

public class NullableTypesExample

{

static int? _testValue;

public static void Main()

{

if(_testValue == null) Console.WriteLine("null");

else

Console.WriteLine(_testValue.ToString());

}

}

Output:

null

GoalKicker.com – C# Notes for Professionals

150

Section 38.6: E ective usage of underlying Nullable<T> argument

Any nullable type is a generic type. And any nullable type is a value type.

There are some tricks which allow to e ectively use the result of the Nullable.GetUnderlyingType method when creating code related to reflection/code-generation purposes:

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)));

}

}

The usage:

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.");

Output:

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.

PS. The NullableTypesCache is defined as follows:

GoalKicker.com – C# Notes for Professionals

151

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) {

// Try to avoid the expensive MakeGenericType method call

return cache.GetOrAdd(type, t => NullableBase.MakeGenericType(t));

}

}

Section 38.7: Check if a generic type parameter is a nullable type

public bool IsTypeNullable<T>()

{

return Nullable.GetUnderlyingType( typeof(T) )!=null;

}

GoalKicker.com – C# Notes for Professionals

152