Ho riscontrato alcuni comportamenti interessanti nell'interazione tra Nullable
e conversioni implicite. Ho trovato che fornire una conversione implicita per un tipo di riferimento da un tipo di valore consente al tipo Nullable
di essere passato a una funzione che richiede il tipo di riferimento quando invece mi aspetto un errore di compilazione. Il seguente codice illustra questo:Qual è la giustificazione per questo comportamento Nullable <T> con operatori di conversione implicita
static void Main(string[] args)
{
PrintCatAge(new Cat(13));
PrintCatAge(12);
int? cat = null;
PrintCatAge(cat);
}
private static void PrintCatAge(Cat cat)
{
if (cat == null)
System.Console.WriteLine("What cat?");
else
System.Console.WriteLine("The cat's age is {0} years", cat.Age);
}
class Cat
{
public int Age { get; set; }
public Cat(int age)
{
Age = age;
}
public static implicit operator Cat(int i)
{
System.Console.WriteLine("Implicit conversion from " + i);
return new Cat(i);
}
}
uscita:
The cat's age is 13 years
Implicit conversion from 12
The cat's age is 12 years
What cat?
Se il codice di conversione viene rimosso dal Cat
allora si ottiene gli errori attesi:
Error 3 The best overloaded method match for 'ConsoleApplication2.Program.PrintCatAge(ConsoleApplication2.Program.Cat)' has some invalid arguments
Error 4 Argument 1: cannot convert from 'int?' to 'ConsoleApplication2.Program.Cat
Se si apre il file eseguibile con ILSpy il codice che è stato generato è il seguente
int? num = null;
Program.PrintCatAge(num.HasValue ? num.GetValueOrDefault() : null);
In un esperimento simile ho rimosso la conversione e ha aggiunto un sovraccarico di PrintCatAge
che prende un int (non nullable) per vedere se il compilatore eseguirebbe un'operazione simile, ma non lo fa.
Capisco cosa sta succedendo, ma non ne capisco la giustificazione. Questo comportamento è inaspettato per me e sembra strano. Non ho avuto successo nel trovare alcun riferimento a questo comportamento su MSDN nella documentazione per le conversioni o Nullable<T>
.
La domanda che pongo allora è, è questo intenzionale e c'è una spiegazione del perché questo sta accadendo?
Interessante! Un comportamento inaspettatamente simile è ((oggetto) (int?) Null) == null che è vero. Un int nullo può essere inserito in un riferimento null. – usr
Lanciare un valore null in questo modo: '(int?) Null' viene ottimizzato. Tuttavia, (null as int?) Provoca la creazione effettiva di un int? variabile temporanea. Ad ogni modo, mi aspetterei 'null == null' in questi casi. – Thomas
@usr: Questo è previsto; il CLR ha un codice speciale per il nulla. In realtà è impossibile ottenere un 'Nullable' in scatola. –
SLaks