Comment convertir un System.Type à sa version nullable?

Encore une fois: “Existe-t-il une manière plus simple de faire les choses au lieu de ma méthode d’assistance?”

Il est donc facile d’obtenir le type sous-jacent d’un type nullable, mais comment puis-je obtenir la version nullable d’un type .NET?

Donc j’ai

typeof(int) typeof(DateTime) System.Type t = something; 

et je veux

 int? DateTime? 

ou

 Nullable (which is the same) if (t is primitive) then Nullable else just T 

Y a-t-il une méthode intégrée?

Voici le code que j’utilise:

 Type GetNullableType(Type type) { // Use Nullable.GetUnderlyingType() to remove the Nullable wrapper if type is already nullable. type = Nullable.GetUnderlyingType(type); if (type.IsValueType) return typeof(Nullable<>).MakeGenericType(type); else return type; } 

J’ai quelques méthodes que j’ai écrites dans ma bibliothèque d’utilitaires sur lesquelles je me suis beaucoup appuyé. Le premier est une méthode qui convertit tout type dans son formulaire Nullable correspondant:

  ///  /// [ public static Type GetNullableType(Type TypeToConvert) ] ///  /// Convert any Type to its Nullable<T> form, if possible ///  /// The Type to convert ///  /// The Nullable<T> converted from the original type, the original type if it was already nullable, or null /// if either  could not be converted or if it was null. ///  ///  /// To qualify to be converted to a nullable form,  must contain a non-nullable value /// type other than System.Void. Otherwise, this method will return a null. ///  ///  public static Type GetNullableType(Type TypeToConvert) { // Abort if no type supplied if (TypeToConvert == null) return null; // If the given type is already nullable, just return it if (IsTypeNullable(TypeToConvert)) return TypeToConvert; // If the type is a ValueType and is not System.Void, convert it to a Nullable if (TypeToConvert.IsValueType && TypeToConvert != typeof(void)) return typeof(Nullable<>).MakeGenericType(TypeToConvert); // Done - no conversion return null; } 

La seconde méthode indique simplement si un type donné est nullable. Cette méthode est appelée par le premier et est utile séparément:

  ///  /// [ public static bool IsTypeNullable(Type TypeToTest) ] ///  /// Reports whether a given Type is nullable (Nullable< Type >) ///  /// The Type to test ///  /// true = The given Type is a Nullable< Type >; false = The type is not nullable, or  /// is null. ///  ///  /// This method tests  and reports whether it is nullable (ie whether it is either a /// reference type or a form of the generic Nullable< T > type). ///  ///  public static bool IsTypeNullable(Type TypeToTest) { // Abort if no type supplied if (TypeToTest == null) return false; // If this is not a value type, it is a reference type, so it is automatically nullable // (NOTE: All forms of Nullable are value types) if (!TypeToTest.IsValueType) return true; // Report whether TypeToTest is a form of the Nullable<> type return TypeToTest.IsGenericType && TypeToTest.GetGenericTypeDefinition() == typeof(Nullable<>); } 

L’implémentation ci-dessus d’IsTypeNullable fonctionne comme un champion à chaque fois, mais elle est légèrement verbeuse et lente dans sa dernière ligne de code. Le corps de code suivant est le même que ci-dessus pour IsTypeNullable, sauf que la dernière ligne de code est plus simple et plus rapide:

  // Abort if no type supplied if (TypeToTest == null) return false; // If this is not a value type, it is a reference type, so it is automatically nullable // (NOTE: All forms of Nullable are value types) if (!TypeToTest.IsValueType) return true; // Report whether an underlying Type exists (if it does, TypeToTest is a nullable Type) return Nullable.GetUnderlyingType(TypeToTest) != null; 

Prendre plaisir!

marque

PS – A propos de la “nullité”

Je devrais répéter une déclaration sur la nullité que j’ai faite dans un article séparé, qui s’applique directement à traiter correctement ce sujet. En d’autres termes, je pense que la discussion ne doit pas porter sur la manière de vérifier si un object est un type Nullable générique, mais plutôt sur la possibilité d’atsortingbuer une valeur null à un object de ce type. En d’autres termes, je pense que nous devrions déterminer si un type d’object est nullable, et non s’il est nullable. La différence réside dans la sémantique, à savoir les raisons pratiques pour déterminer la nullité, ce qui est généralement tout ce qui compte.

Dans un système utilisant des objects dont les types sont peut-être inconnus jusqu’à l’exécution (services Web, appels distants, bases de données, stream, etc.), il est souvent nécessaire de déterminer si une valeur NULL peut être affectée à l’object ou s’il peut contenir un null. Effectuer de telles opérations sur des types non nullables produira probablement des erreurs, généralement des exceptions, qui sont très coûteuses en termes de performances et d’exigences de codage. Pour adopter l’approche hautement préférée consistant à éviter de tels problèmes de manière proactive, il est nécessaire de déterminer si un object d’un Type arbitraire est capable de contenir un null; c’est-à-dire si elle est généralement “nullable”.

Dans un sens très pratique et typique, la nullité dans les termes .NET n’implique pas nécessairement que le type d’un object est une forme de Nullable. Dans de nombreux cas, les objects ont des types de référence, peuvent contenir une valeur nulle et sont donc tous nuls; aucun d’entre eux n’a un type Nullable. Par conséquent, pour des raisons pratiques dans la plupart des scénarios, des tests devraient être effectués pour le concept général de nullité, par opposition au concept de Nullable dépendant de l’implémentation. Nous ne devrions donc pas nous attarder en nous concentrant uniquement sur le type .NET Nullable, mais en incorporant plutôt notre compréhension de ses exigences et de son comportement dans le processus de focalisation sur le concept pratique général de la nullité.

La réponse de Lyman est géniale et m’a aidé, cependant, il y a un autre bug qui doit être corrigé.

Nullable.GetUnderlyingType(type) ne devrait être appelé que si le type n’est pas déjà un type Nullable . Sinon, il semble retourner à tort la valeur null lorsque le type dérive de System.RuntimeType (par exemple, lorsque je typeof(System.Int32) ). La version ci-dessous évite d’avoir à appeler Nullable.GetUnderlyingType(type) en vérifiant si le type est Nullable place.

Vous trouverez ci-dessous une version d’ ExtensionMethod de cette méthode qui retournera immédiatement le type sauf s’il s’agit d’un ValueType qui n’est pas déjà Nullable .

 Type NullableVersion(this Type sourceType) { if(sourceType == null) { // Throw System.ArgumentNullException or return null, your preference } else if(sourceType == typeof(void)) { // Special Handling - known cases where Exceptions would be thrown return null; // There is no Nullable version of void } return !sourceType.IsValueType || (sourceType.IsGenericType && sourceType.GetGenericTypeDefinition() == typeof(Nullable<>) ) ? sourceType : typeof(Nullable<>).MakeGenericType(sourceType); } 

(Je suis désolé, mais je ne pouvais pas simplement poster un commentaire sur la réponse de Lyman parce que j’étais nouveau et que je n’avais pas encore assez de représentant.)

Il n’y a rien de construit que je sache, comme l’ int? , etc. est simplement du sucre syntaxique pour Nullable ; et ne reçoit pas de traitement spécial au-delà de cela. Il est particulièrement improbable que vous tentiez d’obtenir ceci à partir des informations de type d’un type donné. Généralement, cela nécessite toujours un code «rouler soi-même». Vous devez utiliser Reflection pour créer un nouveau type Nullable avec le paramètre type du type d’entrée.

Edit: Comme le suggèrent les commentaires, Nullable<> est traité spécialement, et dans le runtime pour démarrer comme expliqué dans cet article .