web-dev-qa-db-fra.com

Tapez int? vs type int

J'ai cette comparaison qui équivaut à false comme prévu

bool eq = typeof(int?).Equals(typeof(int));

maintenant j'ai ce code

List<object> items = new List<object>() { (int?)123 };
int result = items.OfType<int>().FirstOrDefault();

mais cela renvoie 123 - de toute façon cette valeur est de type int?

Comment se peut-il?

45
Dr. Snail

Les types nullables ont des règles spéciales de "boxe"; "boxing" est lorsqu'un type de valeur est traité comme object, selon votre code. Contrairement aux types de valeur normaux, un type de valeur nullable est encadré soit comme null (régulier null, pas de type), soit comme non nullable type (le T dans T?). Donc: un int? Est encadré comme un int, pas un int?. Ensuite, lorsque vous utilisez OfType<int>() dessus, vous obtenez toutes les valeurs qui sont int, ce qui est: la valeur unique que vous avez passée, car elle est de type int.

59
Marc Gravell

Un type de valeur nullable est encadré par les règles suivantes

  • Si HasValue renvoie false, la référence nulle est produite.
  • Si HasValue renvoie true, une valeur du type de valeur sous-jacent T est encadrée, pas l'instance de nullable.

Dans votre exemple, la deuxième règle a été suivie car vous avez une valeur:

var i = (object)(int?)123;
9
Johnny

Il est un peu tard, mais à côté de la réponse de Marc à votre question, je veux donner quelques informations supplémentaires sur les types de valeur Nullable dans CLR.

Le CLR a un support intégré pour les types de valeur nullable. Ce support spécial est fourni pour boxe, déballage, appel GetType, appel des méthodes d'interface .

Par exemple, vérifions GetType():

Int32? x = 5;
Console.WriteLine(x.GetType());

Que pensez-vous qu'il imprimera sur la console? System.Nullable<Int32? Non, le résultat est System.Int32.

Ou bien, cochez la case, que vous avez notée dans votre question:

Int32? n =5;
Object o = n;
Console.WriteLine("o's type={0}", o.GetType()); // "System.Int32"

La règle est que:

Lorsque le CLR met en boîte une instance Nullable, il vérifie si elle est nulle, et si c'est le cas, le CLR ne met rien en boîte et null est renvoyé. Si l'instance nullable n'est pas null, le CLR prend la valeur de l'instance nullable et la met en boîte. En d'autres termes, un Nullable avec une valeur de 5 est encadré dans un boxed-Int32 avec une valeur de 5.

Et, à la fin, je veux expliquer comment CLR ajoute un support spécial pour appeler des méthodes d'interface à partir de types Nullable. Jetons un coup d'œil à cela:

Int32? n = 5;
Int32 result = ((IComparable) n).CompareTo(5); // Compiles & runs OK
Console.WriteLine(result); // 0

Dans le code précédent, je casse n, un Nullable<Int32>, à IComparable<Int32>, un type d'interface. Cependant, le Nullable<T> le type n'implémente pas le IComparable<Int32> interface comme Int32 Est-ce que. Le compilateur C # permet quand même de compiler ce code.

4
Farhad Jabiyev