J'ai suivi avec intérêt la fonctionnalité d'opérateur de navigation sécurisée ajoutée en C # 6. J'attendais cela avec impatience depuis un moment. Mais je trouve un comportement différent de celui auquel je m'attendais. Je réalise que je ne comprends vraiment pas comment cela fonctionne réellement.
Étant donné cette classe
class Foo {
public int? Measure;
}
Voici un code utilisant le nouvel opérateur.
Foo f = new Foo { Measure = 3 };
Console.WriteLine(f?.Measure); // 3
f = new Foo { Measure = null };
Console.WriteLine(f?.Measure); // null
f = null;
Console.WriteLine(f?.Measure); // null
Jusqu'ici, tout fonctionne comme prévu. ?.
accède aux membres lorsque le côté gauche n'est pas null, sinon il renvoie null. Mais ici les choses vont dans une direction à laquelle je ne m'attendais pas.
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null
Quoi?
Pourquoi puis-je obtenir HasValue
à partir de i
, mais pas à partir de la même expression que j'ai attribuée à i
? Comment HasValue
peut-il être nul?
Edit: Ma vraie question concerne le comportement du programme, pas une erreur de compilation. J'ai supprimé les éléments supplémentaires relatifs à la compilation et concentré plus précisément cette question sur les raisons pour lesquelles deux résultats différents sont renvoyés par ce qui semble être la même logique.
Passons à travers cette logique.
var f = ???;
var i = f?.Measure;
var t = i.HasValue;
Nous ne savons pas si f
est nul ou non.
f
est null, le résultat (i
) est null
f
n'est pas null, alors le résultat (i
) est un int
Par conséquent, i
est défini comme int?
et t
est un bool
Passons maintenant à travers ceci:
var f = ???;
var i = f?.Measure.HasValue;
f
est null, alors le résultat (i
) est nul f
n'est pas null, le résultat (i
) est Measure.HasValue
, ce qui est un bool. Par conséquent, i
est un bool?
.
Si f
est null, nous court-circuitons et renvoyons null. Si ce n'est pas le cas, nous renvoyons le résultat bool
de .HasValue
.
En règle générale, lorsque vous utilisez ?.
, le type de retour doit être une valeur de référence ou un Nullable<T>
, car l'expression peut court-circuiter pour renvoyer null.
Nullable<T>
est en fait une structure et ne peut donc pas être null, seule sa Value
peut le faire, donc HasValue
sera toujours accessible.
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null
Dans ce cas, f est nul.
La raison pour laquelle i.HasValue
a retourné false
est parce que i
est de type Nullable<int>
. Ainsi, même lorsque la valeur de i
est null, comme dans ce cas, i.HasValue
est toujours accessible.
Cependant, f?.Measure.HasValue
renvoie immédiatement null
après que f?
soit évalué. D'où le résultat que vous voyez ci-dessus.
Juste pour citer commentaire de Rob :
La principale chose à réaliser est que vous lisez et comprenez this: f? .Mesure .Value comme ceci: (f? .Mesure). ne pas.