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


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow