J'ai fait quelques recherches à ce sujet en utilisant différentes méthodes pour attribuer des valeurs à un entier nullable. Voici ce qui s'est passé lorsque j'ai fait diverses choses. Devrait clarifier ce qui se passe. Gardez à l'esprit: Nullable<something>ou le raccourci something?est une structure pour laquelle le compilateur semble faire beaucoup de travail pour nous permettre d'utiliser avec null comme s'il s'agissait d'une classe. 
Comme vous le verrez ci-dessous, SomeNullable == nullet SomeNullable.HasValueretournera toujours un vrai ou un faux attendu. Bien que cela ne soit pas démontré ci-dessous, il SomeNullable == 3est également valide (en supposant que SomeNullable est un int?). 
Alors que SomeNullable.Valuenous obtient une erreur d'exécution si nous avons attribué nullà SomeNullable. C'est en fait le seul cas où nullables pourrait nous poser problème, grâce à une combinaison d'opérateurs surchargés, surchargésobject.Equals(obj) méthode, et optimisation du compilateur et entreprise de singe.
Voici une description du code que j'ai exécuté et de la sortie qu'il a produite dans les étiquettes:
int? val = null;
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Ok, essayons la prochaine méthode d'initialisation:
int? val = new int?();
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Tout comme avant. Gardez à l'esprit que l'initialisation avec int? val = new int?(null);, avec null passé au constructeur, aurait produit une erreur de temps de compilation, car la valeur de l'objet nullable n'est PAS nullable. Seul l'objet wrapper lui-même peut être égal à null.
De même, nous obtiendrions une erreur de temps de compilation de:
int? val = new int?();
val.Value = null;
sans compter que val.Valuec'est une propriété en lecture seule de toute façon, ce qui signifie que nous ne pouvons même pas utiliser quelque chose comme:
val.Value = 3;
mais encore une fois, les opérateurs de conversion implicites surchargés polymorphes nous permettent de faire:
val = 3;
Pas besoin de s'inquiéter de tout ce qui peut arriver, tant qu'il fonctionne bien? :)