web-dev-qa-db-fra.com

Opérateur de navigation C # Safe - que se passe-t-il réellement?

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.

17
recursive

Passons à travers cette logique.

var f = ???;
var i = f?.Measure;
var t = i.HasValue;

Nous ne savons pas si f est nul ou non. 

  1. Si fest null, le résultat (i) est null 
  2. Si fn'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;
  1. Si fest null, alors le résultat (i) est nul 
  2. Si fn'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.

19
Rob

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.

0
Spencer Hakim
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.

0
user69234