2010-01-08 3 views
13

Avez-vous déjà essayé d'utiliser la méthode Convert.ChangeType() pour convertir une valeur en type Nullable<T>? Bizarrement, il lancera un InvalidCastException indiquant "Un objet nul ne peut pas être converti en un type de valeur".Pourquoi les valeurs Nullables <T> sont-elles considérées comme un type de valeur?

Essayez de lancer sur votre fenêtre immédiate: ?System.Convert.ChangeType(null, typeof(int?))

Pour une raison obscure, Nullables sont les types de valeur considérée. Par exemple, typeof(int?).IsValueType renvoie true.

Pour moi, depuis Nullable<T> accepter null, c'est un type de classe, pas un type de valeur. Est-ce que quelqu'un sait pourquoi il serait mis en œuvre différemment?

Répondre

27

System.Nullable<T> est techniquement une structure, il est donc un type de valeur (la valeur null pour une Nullable<T> est pas exactement la même chose comme une référence null. Il est un drapeau booléen qui indique l'absence d'une valeur). Cependant, elle est traitée spécialement par le runtime et cela en fait un type de valeur maladroit. Premièrement, il ne satisfait pas la contrainte de type where T : struct (il ne satisfait pas non plus where T : class, pour ce que ça vaut). Deuxièmement, il présente un comportement de boxe intéressant. Boxe un Nullable<T> se traduira par:

  • Une référence null, si la valeur est null.
  • Valeur encadrée du sous-jacente de type si elle contient effectivement une valeur. Autrement dit, dans les déclarations:

    int? x = 2; 
    object y = x; 
    

    y est pas un Nullable<int> boxed. C'est simplement une boîte int. Vous pouvez déballer n'importe quelle valeur encadrée de type T à Nullable<T> (et T, bien sûr). La diffusion d'une référence null à Nullable<T> donne une valeur de null (comme vous pouvez vous y attendre).

Ce traitement spécial par le moteur d'exécution rend les types nullables fonctionnent plus semblable à la façon dont null œuvres dans les types de référence.

+3

L'étrange comportement de boxe prend du temps à comprendre - mais je suis content que ce soit comme ça; sinon, une grande partie de la valeur de 'Nullable ' (qui provient de la transparence des valeurs) serait perdue. – LBushkin

+1

En fait, le comportement de boxe était un changement qui s'est produit tard dans le cycle de développement de .NET 2.0. Au début des bêtas, 'Nullable ' était une structure simple. En pratique, lorsque vous utilisez réellement des types nullables pour stocker des valeurs inexistantes, je pense aussi que ce comportement est plus naturel. –

+0

Excellente information ajoutée par le chemin – Nick

11

Nullable<T> est un type de valeur (il est un struct, voir dans le MSDN documentation), mais il y a une conversion implicite de null à un Nullable<T> sans valeur (x.HasValue == false). Il existe également une conversion implicite des valeurs de type T en valeurs de type Nullable<T>.

En outre, tous les opérateurs sont levés des types standard pour travailler directement avec des types Nullable.

+0

Pourquoi le downvote? Je me trompe? Si oui, s'il vous plaît, éclairez-moi. –

+0

J'ai mis à jour pour annuler downvote. :) –

2

Nullable<T> est implémentée en tant que struct et les structures sont des types de valeur.

+1

Mais aucune structure ne peut recevoir une valeur null. Je crois que les Nullables sont assez différents des structs pour ne pas être considérés comme des structs. – jpbochi

+2

'Nullable ' ne peut pas non plus recevoir une valeur 'null', il a juste une conversion implicite vers et depuis' null'. Vous pouvez implémenter ceci sur n'importe quelle 'struct' personnalisée, si vous le désirez. – Aaronaught

+4

@Aaronaught: vous pouvez faire quelque chose * similaire * avec une structure personnalisée, mais une grande partie du comportement des types nullables ne peut pas être imitée par le code. Les valeurs nullables ne sont pas simplement une solution de bibliothèque. Ils obtiennent un soutien spécial du compilateur (et le CLR aussi, je pense). –

1

Je viens de voir cette question dans la liste des "questions connexes" au Why Nullable<T> is a struct? et je pense que ma réponse s'applique ici aussi. Le point entier de Nullable<T> est d'agir comme un type de valeur à tous égards, sauf pour la possibilité de prendre une valeur nulle.

La valeur nulle d'une référence nulle peut être consultée de deux manières.L'un est qu'il ne référence rien, l'autre est qu'il n'a aucune valeur significative. Ces choses sont à peu près deux façons différentes de dire la même chose, mais elles ont des utilisations différentes.

Nullable<T> nous donne la possibilité de dire "ceci n'a pas de valeur significative" et dans cette mesure il peut avoir la même sémantique qu'une référence nulle, mais ce n'est pas comme une référence d'une autre manière. Lorsqu'elle est nulle, sa nullité est purement que «aucune valeur significative» n'est nulle - pas «ne fait référence à rien» et lorsqu'elle n'est pas nulle, elle contient une valeur, sans s'y référer. (Aaronaught soutient que cela signifie qu'un Nullable ne peut pas vraiment contenir de null, alors que je ne suis pas d'accord parce qu'au niveau où il l'utilise peut avoir une nullité sémantique, son point vaut la peine d'être pris en compte même quand "null" un Nullable est différent d'une référence - en réalité, notre désaccord dépend du niveau d'abstraction que nous choisissons d'utiliser).

Questions connexes