web-dev-qa-db-fra.com

Pourquoi l'incrémentation de Nullable <int> ne déclenche-t-elle pas une exception?

Pourriez-vous expliquer, pourquoi Console.WriteLine écrit une ligne vide (Console.WriteLine(null) me donne une erreur de compilation) et pourquoi il n'y a pas NullReferenceException (même a+=1 ne devrait pas le soulever)?

int? a = null;
a++; // Why there is not NullReferenceException? 
Console.WriteLine(a); // Empty line
97
FSou1

Vous observez les effets d'un opérateur levé.

De la section 7.3.7 de la spécification C # 5:

Les opérateurs levés permettent aux opérateurs prédéfinis et définis par l'utilisateur qui fonctionnent sur des types de valeurs non nullables d'être également utilisés avec des formes nullables de ces types. Les opérateurs levés sont construits à partir d'opérateurs prédéfinis et définis par l'utilisateur qui répondent à certaines exigences, comme décrit ci-dessous:

  • Pour les opérateurs unaires + ++ - -- ! ~ une forme levée d'un opérateur existe si l'opérande et les types de résultat sont tous deux des types de valeurs non nullables. La forme levée est construite en ajoutant un seul ? modificateur aux types opérande et résultat. L'opérateur levé produit une valeur nulle si l'opérande est nul. Sinon, l'opérateur levé déballe l'opérande, applique l'opérateur sous-jacent et encapsule le résultat.

Donc en gros, a++ dans ce cas est une expression avec un résultat de null (comme un int?) et la variable reste intacte.

Quand vous appelez

Console.WriteLine(a);

qui est encadré dans object, qui le convertit en une référence nulle, qui est imprimée comme une ligne vide.

121
Jon Skeet

La réponse de Jon est correcte mais j'ajouterais quelques notes supplémentaires.

Pourquoi Console.WriteLine(null) donne-t-il une erreur de compilation?

Il y a 19 surcharges de Console.WriteLine Et trois d'entre elles s'appliquent à un null: celui qui prend un string, celui qui prend un char[] Et celui qui prend un object. C # ne peut pas déterminer laquelle de ces trois vous voulez dire, il donne donc une erreur. Console.WriteLine((object)null) serait légal car maintenant c'est clair.

pourquoi Console.WriteLine(a) écrit une ligne vide?

a est un int? nul. La résolution de surcharge choisit la version object de la méthode, de sorte que int? Est encadré avec une référence nulle. C'est donc fondamentalement la même chose que Console.WriteLine((object)null), qui écrit une ligne vide.

Pourquoi n'y a-t-il pas NullReferenceException sur l'incrément?

Où est le null référence qui vous inquiète? a est un int? nul qui n'est pas un type de référence pour commencer! N'oubliez pas que les types de valeur nullable sont types de valeur, pas types de référence, donc ne vous attendez pas à ce qu'ils aient une sémantique de référence à moins qu'ils ne soient encadrés dans un type de référence. Il n'y a pas de boxe dans l'addition.

115
Eric Lippert

Incrémentez-vous null ???

int? a = null;
a++;

Cette instruction signifie simplement null++ C'est-à-dire null + 1.

Selon ce document, un type Nullable peut représenter la plage correcte de valeurs pour son type de valeur sous-jacent, plus une valeur NULL supplémentaire. peut être attribué la valeur nulle

Ici, vous incrémentez null, puis il deviendra une valeur nulle et non pas 0 ou tout autre entier.

Pourquoi il imprime vierge au lieu d'erreur ??

lorsque vous imprimez un type nullable avec une valeur nulle, il s'imprime en blanc au lieu d'une erreur car vous imprimez une variable, c'est-à-dire la valeur d'un emplacement mémoire. qui peut être nul ou tout entier.

Mais lorsque vous essayez d'imprimer null en utilisant Console.WriteLine(null), puisque null n'est pas une variable, il ne fait donc référence à aucun emplacement de mémoire. Et donc cela donne une erreur "NullReferenceException".

Alors, comment pouvez-vous imprimer n'importe quel entier en utilisant Console.WriteLine(2); ??

Dans ce cas, 2 sera mis en mémoire à un emplacement temporaire et le pointeur pointe vers cet emplacement de mémoire à imprimer.

0
Laxmikant Dange