C# Language
Types nullables
Recherche…
Syntaxe
-
Nullable<int> i = 10;
- int? j = 11;
- int? k = null;
- DateTime? DateOfBirth = DateTime.Now;
- décimal? Quantité = 1,0 m;
- bool? IsAvailable = true;
- carboniser? Lettre = 'a';
- (type)? Nom de variable
Remarques
Les types nullables peuvent représenter toutes les valeurs d'un type sous-jacent, ainsi que null
.
La syntaxe T?
est un raccourci pour Nullable<T>
Les valeurs nullables sont en System.ValueType
objets System.ValueType
, elles peuvent donc être encapsulées ou non. En outre, la valeur null
d'un objet nullable n'est pas la même que la valeur null
d'un objet de référence, c'est simplement un indicateur.
Lors de la mise en boîte d'un objet nullable, la valeur null est convertie en référence null
et la valeur non null est convertie en type sous-jacent non nullable.
DateTime? dt = null;
var o = (object)dt;
var result = (o == null); // is true
DateTime? dt = new DateTime(2015, 12, 11);
var o = (object)dt;
var dt2 = (DateTime)dt; // correct cause o contains DateTime value
La seconde règle conduit à un code correct mais paradoxal:
DateTime? dt = new DateTime(2015, 12, 11);
var o = (object)dt;
var type = o.GetType(); // is DateTime, not Nullable<DateTime>
En bref:
DateTime? dt = new DateTime(2015, 12, 11);
var type = dt.GetType(); // is DateTime, not Nullable<DateTime>
Initialiser un nullable
Pour null
valeurs null
:
Nullable<int> i = null;
Ou:
int? i = null;
Ou:
var i = (int?)null;
Pour les valeurs non nulles:
Nullable<int> i = 0;
Ou:
int? i = 0;
Vérifier si un Nullable a une valeur
int? i = null;
if (i != null)
{
Console.WriteLine("i is not null");
}
else
{
Console.WriteLine("i is null");
}
Ce qui est le même que:
if (i.HasValue)
{
Console.WriteLine("i is not null");
}
else
{
Console.WriteLine("i is null");
}
Récupère la valeur d'un type nullable
Donné après nullable int
int? i = 10;
Si une valeur par défaut est nécessaire, vous pouvez en affecter un en utilisant un opérateur de coalescence null , la méthode GetValueOrDefault
ou vérifier si HasValue
int HasValue
avant l'affectation.
int j = i ?? 0;
int j = i.GetValueOrDefault(0);
int j = i.HasValue ? i.Value : 0;
L'utilisation suivante est toujours dangereuse . Si i
est nul à l'exécution, une System.InvalidOperationException
sera lancée. Au moment de la conception, si une valeur n'est pas définie, vous obtiendrez une erreur d' Use of unassigned local variable 'i'
.
int j = i.Value;
Obtenir une valeur par défaut à partir d'un nullable
La méthode .GetValueOrDefault()
renvoie une valeur même si la propriété .HasValue
est .HasValue
false (contrairement à la propriété Value, qui génère une 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
}
}
Sortie:
0
1
Vérifier si un paramètre de type générique est un type nullable
public bool IsTypeNullable<T>()
{
return Nullable.GetUnderlyingType( typeof(T) )!=null;
}
La valeur par défaut des types nullables est null
public class NullableTypesExample
{
static int? _testValue;
public static void Main()
{
if(_testValue == null)
Console.WriteLine("null");
else
Console.WriteLine(_testValue.ToString());
}
}
Sortie:
nul
Utilisation efficace des Nullables sous-jacents argument
Tout type nullable est un type générique . Et tout type nullable est un type de valeur .
Il y a quelques astuces qui permettent d' utiliser efficacement le résultat de la méthode Nullable.GetUnderlyingType lors de la création de code lié à des fins de réflexion / génération de code:
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)));
}
}
L'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.");
Sortie:
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 Le NullableTypesCache
est défini comme suit:
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));
}
}