44 votes

Le type Nullable n'est pas un type NULLABLE?

Je faisais quelques tests avec des types nullables, et cela n'a pas fonctionné comme prévu:

 int? testInt = 0;
Type nullableType = typeof(int?);
Assert.AreEqual(nullableType, testInt.GetType()); // not the same type
 

Cela ne marche pas non plus:

 DateTime? test = new DateTime(434523452345);
Assert.IsTrue(test.GetType() == typeof(Nullable)); //FAIL 

DateTime? test = new DateTime(434523452345);
Assert.IsTrue(test.GetType() == typeof(Nullable<>)); //STILL FAIL
 

Ma question est la suivante: pourquoi testInt.GetType () renvoie-t-il int, et typeof (int?) Renvoie-t-il le véritable type nullable?

56voto

Romain Verdier Points 8699

Selon la MSDN :

L'appel de GetType sur un type Nullable les causes d'un boxe de l'opération effectuée lorsque le type est implicitement converti à l'Objet. Donc GetType toujours retourne un objet de Type que représente le type sous-jacent, pas le type Nullable.

Lorsque vous zone un objet nullable, seul le type sous-jacent est en boîte.

Encore une fois, à partir de MSDN :

Boxe une valeur non nulle nullable type de valeur les boîtes du type de la valeur elle-même, pas la Système.Nullable qui encapsule la valeur type.

22voto

LukeH Points 110965

Suite à Romain de la bonne réponse, si vous voulez comparer la "vraie" types (c'est à dire sans implicitement la conversion de tout type nullable à son type sous-jacent), alors vous pouvez créer une extension de la méthode comme suit:

public static class MyExtensionMethods
{
    public static Type GetRealType<T>(this T source)
    {
        return typeof(T);
    }
}

Et puis essayer les tests suivants:

int? a = 0;
Console.WriteLine(a.GetRealType() == typeof(int?));         // True
Console.WriteLine(a.GetRealType() == typeof(int));          // False

int b = 0;
Console.WriteLine(b.GetRealType() == typeof(int));          // True
Console.WriteLine(b.GetRealType() == typeof(int?));         // False

DateTime? c = DateTime.Now;
Console.WriteLine(c.GetRealType() == typeof(DateTime?));    // True
Console.WriteLine(c.GetRealType() == typeof(DateTime));     // False

DateTime d = DateTime.Now;
Console.WriteLine(d.GetRealType() == typeof(DateTime));     // True
Console.WriteLine(d.GetRealType() == typeof(DateTime?));    // False

EDIT...

Pour l'exhaustivité -- et invité par SLaks les commentaires ci-dessous -- voici une version alternative qui utilise uniquement le type de compilation lors de l' source est soit null ou Nullable<>; sinon, il utilise GetType et renvoie le runtime type:

public static class MyExtensionMethods
{
    public static Type GetRealType<T>(this T source)
    {
        Type t = typeof(T);

        if ((source == null) || (Nullable.GetUnderlyingType(t) != null))
            return t;

        return source.GetType();
    }
}

3voto

supercat Points 25534

Bien que le C# prétend que la valeur de type emplacements de stockage tenir les instances des types dérivés de System.ValueType, qui à son tour dérive System.Object, qui n'est pas vraiment vrai. Chaque type dérivé de System.ValueType représente en fait deux types très différents de choses:

  1. Une collection d'octets qui (pour les types primitifs) représente les données directement, ou (pour les non-primitif types de structure) détient le contenu de tous les champs, publics et privés, mais ne détient aucune information de type.
  2. Autonome tas d'objet, qui contient un objet-tête en plus de la ci-dessus, dont le type est dérivé de " Système.ValueType`.

Les emplacements de stockage d'un type de valeur de la tenue de la première; tas d'objets d'un type de valeur de la seconde.

Pour diverses raisons, Microsoft a décidé que Nullable<T> ne devrait soutenir la première utilisation. Si l'on tente de passer un emplacement de stockage de type Nullable<T> code qui attend une référence à un objet tas, le système va convertir l'élément à un T si HasValue est vrai, ou bien tout simplement passer une référence null si HasValue est faux. Bien qu'il existe de façons de créer un tas d'objet de type Nullable<T>, les méthodes normales de convertir une valeur de type emplacement de stockage pour un tas d'objet ne sera jamais en produire un.

Notez également que l'appelant GetType() de la valeur d'emplacement de stockage ne sera pas réellement d'évaluer le type de l'emplacement de stockage, mais au lieu de convertir le contenu de l'emplacement de stockage à un tas d'objets et de retourner ensuite le type de l'objet. Parce que les emplacements de stockage de type Nullable<T> convertis, soit pour les instances d'objet T ou null, rien dans l'instance d'un objet permettra de dire si l'emplacement de stockage à partir de laquelle il est venu a été un Nullable<T>.

0voto

donkanmcleod Points 19

Un moyen simple de vérifier qu’il utilise l’opérateur "is":

 (i is Nullable<int>) || (i is Nullable<long>) || (i is Nullable<float>) || (i is Nullable<short>)
 

J'ai pensé lire ces deux pages MSDN:

http://msdn.microsoft.com/en-us/library/ms366789(v=vs.90).aspx

http://msdn.microsoft.com/en-us/library/ms228597%28v=VS.90%29.aspx

À votre santé!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X