Perché l'incremento di Nullable <int> non genera un'eccezione?


98

Potresti per favore spiegare, perché Console.WriteLine scrive una riga vuota ( Console.WriteLine(null)dammi un errore di compilazione) e perché non c'è NullReferenceException (anche a+=1se non dovrebbe sollevarla)?

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

Tutti i tre operatori ++, +=e +hanno sollevato varianti. Pertanto le dichiarazioni a++;, a += 1;e a = a + 1;sono tutte consentite. Ogni prodotto null(nessuna eccezione generata) se aè inizialmente null.
Jeppe Stig Nielsen

5
NullReferenceException? ma int?non è un Reference, è solo un intche può prendere nullvalore
Khaled.K

Risposte:


124

Stai osservando gli effetti di un operatore sollevato .

Dalla sezione 7.3.7 della specifica C # 5:

Gli operatori lifted consentono agli operatori predefiniti e definiti dall'utente che operano su tipi di valore non nullable di essere utilizzati anche con forme nullable di tali tipi. Gli operatori sollevati sono costruiti da operatori predefiniti e definiti dall'utente che soddisfano determinati requisiti, come descritto di seguito:

  • Per gli operatori unari + ++ - -- ! ~ esiste una forma elevata di operatore se i tipi di operando e risultato sono entrambi tipi di valore non annullabili. La forma rialzata viene costruita aggiungendo un singolo ?modificatore ai tipi di operando e risultato. L'operatore lifted produce un valore nullo se l'operando è nullo. In caso contrario, l'operatore sollevato scarta l'operando, applica l'operatore sottostante e avvolge il risultato.

Quindi, a++in pratica, in questo caso è un'espressione con un risultato di null(come an int?) e la variabile non viene modificata.

Quando chiami

Console.WriteLine(a);

che viene boxed object, che lo converte in un riferimento nullo, che viene stampato come una riga vuota.


3
C'è un modo per stampare "null" senza usare Console.WriteLine(a == null ? "null" : a)?
Cole Johnson il

5
@Cole Johnson: Console.WriteLine (a ?? "null"); :)
David Chappelle

2
@DavidChappelle Quando aè di tipo int?, direi a ?? "null"che non trova un tipo comune per i due operandi. Hai bisogno di un suggerimento che objectsia il tipo comune. Quindi esegui il cast di entrambi gli operandi. L' asono imballati. Ad esempio ((object)a) ?? "null"o a ?? (object)"null".
Jeppe Stig Nielsen

super. puoi collegarti alla specifica? possiamo definirlo quando sovraccarichiamo gli operatori nelle nostre classi?
Phil

@teabaggs: non riesco a collegarmi facilmente in questo momento e il collegamento sarebbe solo a un documento di Word (che puoi trovare abbastanza facilmente con una ricerca). Si ottengono automaticamente gli operatori sollevati quando si definiscono i sovraccarichi degli operatori, ove appropriato.
Jon Skeet

116

La risposta di Jon è corretta ma aggiungerei alcune note aggiuntive.

Perché Console.WriteLine(null)dà un errore di compilazione?

Ci sono 19 sovraccarichi di Console.WriteLinee tre sono applicabili a a null: quello che prende a string, quello che prende a char[]e quello che prende un object. C # non è in grado di determinare quale di questi tre intendi, quindi restituisce un errore. Console.WriteLine((object)null)sarebbe legale perché ora è chiaro.

perché Console.WriteLine(a)scrive una riga vuota?

aè un null int?. La risoluzione dell'overload sceglie la objectversione del metodo, quindi int?è boxed a un riferimento null. Quindi questo è fondamentalmente lo stesso di Console.WriteLine((object)null), che scrive una riga vuota.

Perché non c'è NullReferenceExceptionsull'incremento?

Dov'è il riferimento nullo di cui sei preoccupato? aè un null int?che non è un tipo di riferimento per cominciare! Ricorda, i tipi di valore nullable sono tipi di valore , non tipi di riferimento , quindi non aspettarti che abbiano una semantica di riferimento a meno che non siano raggruppati in un tipo di riferimento. Non c'è boxe in aggiunta.


0

Stai incrementando null ???

int? a = null;
a++;

Questa affermazione significa semplicemente null++cioè null + 1.

In base a questo documento, un tipo nullable può rappresentare l'intervallo di valori corretto per il tipo di valore sottostante, più un valore null aggiuntivo.A Nullable, pronunciato "Nullable of Int32", può essere assegnato qualsiasi valore da -2147483648 a 2147483647, oppure può essere assegnato il valore nullo

Qui stai incrementando null, quindi diventerà un valore nullo diverso da 0 o da qualsiasi altro numero intero.

Perché stampa in bianco invece di errore?

quando si stampa un tipo nullable con valore null, viene stampato vuoto invece di errore perché si stampa una variabile, ad esempio il valore di una posizione di memoria. che può essere nullo o qualsiasi numero intero.

Ma quando provi a stampare null usando Console.WriteLine(null), poiché null non è una variabile, quindi non si riferisce a nessuna posizione di memoria. E quindi dà errore "NullReferenceException".

Allora come puoi stampare qualsiasi numero intero usando Console.WriteLine(2);??

In questo caso, 2 entrerà in memoria in una posizione temporanea e il puntatore punta a quella posizione di memoria per la stampa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.