Il y a deux problèmes ici: 1) tester pour voir si un type est nullable; et 2) tester pour voir si un objet représente un type nullable.
Pour le problème 1 (test d'un type), voici une solution que j'ai utilisée dans mes propres systèmes: solution TypeIsNullable-check
Pour le problème 2 (test d'un objet), la solution de Dean Chalk ci-dessus fonctionne pour les types de valeur, mais elle ne fonctionne pas pour les types de référence, car l'utilisation de la surcharge <T> renvoie toujours false. Étant donné que les types de référence sont intrinsèquement nullables, le test d'un type de référence doit toujours retourner true. Veuillez consulter la note [À propos de la «nullité»] ci-dessous pour une explication de ces sémantiques. Voici donc ma modification de l'approche de Dean:
public static bool IsObjectNullable<T>(T obj)
{
// If the parameter-Type is a reference type, or if the parameter is null, then the object is always nullable
if (!typeof(T).IsValueType || obj == null)
return true;
// Since the object passed is a ValueType, and it is not null, it cannot be a nullable object
return false;
}
public static bool IsObjectNullable<T>(T? obj) where T : struct
{
// Always return true, since the object-type passed is guaranteed by the compiler to always be nullable
return true;
}
Et voici ma modification du code client-test pour la solution ci-dessus:
int a = 123;
int? b = null;
object c = new object();
object d = null;
int? e = 456;
var f = (int?)789;
string g = "something";
bool isnullable = IsObjectNullable(a); // false
isnullable = IsObjectNullable(b); // true
isnullable = IsObjectNullable(c); // true
isnullable = IsObjectNullable(d); // true
isnullable = IsObjectNullable(e); // true
isnullable = IsObjectNullable(f); // true
isnullable = IsObjectNullable(g); // true
La raison pour laquelle j'ai modifié l'approche de Dean dans IsObjectNullable <T> (T t) est que son approche d'origine renvoyait toujours false pour un type de référence. Puisqu'une méthode comme IsObjectNullable devrait être capable de gérer des valeurs de type référence et puisque tous les types de référence sont intrinsèquement nullables, alors si un type de référence ou un null est passé, la méthode doit toujours retourner true.
Les deux méthodes ci-dessus peuvent être remplacées par la méthode unique suivante et obtenir le même résultat:
public static bool IsObjectNullable<T>(T obj)
{
Type argType = typeof(T);
if (!argType.IsValueType || obj == null)
return true;
return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
}
Cependant, le problème avec cette dernière approche à méthode unique est que les performances souffrent lorsqu'un paramètre Nullable <T> est utilisé. Il faut beaucoup plus de temps au processeur pour exécuter la dernière ligne de cette seule méthode que pour permettre au compilateur de choisir la deuxième surcharge de méthode indiquée précédemment lorsqu'un paramètre de type Nullable <T> est utilisé dans l'appel IsObjectNullable. Par conséquent, la solution optimale consiste à utiliser l'approche à deux méthodes illustrée ici.
CAVEAT: cette méthode ne fonctionne de manière fiable que si elle est appelée à l'aide de la référence d'objet d'origine ou d'une copie exacte, comme indiqué dans les exemples. Cependant, si un objet nullable est encadré dans un autre type (tel qu'un objet, etc.) au lieu de rester dans sa forme Nullable <> d'origine, cette méthode ne fonctionnera pas de manière fiable. Si le code appelant cette méthode n'utilise pas la référence d'objet d'origine non encadrée ou une copie exacte, il ne peut pas déterminer de manière fiable la nullité de l'objet à l'aide de cette méthode.
Dans la plupart des scénarios de codage, pour déterminer la nullité, il faut plutôt s'appuyer sur le test du type de l'objet d'origine, et non sur sa référence (par exemple, le code doit avoir accès au type d'origine de l'objet pour déterminer la nullité). Dans ces cas plus courants, IsTypeNullable (voir lien) est une méthode fiable pour déterminer la nullité.
PS - À 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 pour aborder correctement ce sujet. C'est-à-dire que je pense que l'objectif de la discussion ici ne devrait pas être de savoir comment vérifier si un objet est un type Nullable générique, mais plutôt si l'on peut attribuer une valeur nulle à un objet de son type. En d'autres termes, je pense que nous devrions déterminer si un type d'objet 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é, qui est généralement tout ce qui compte.
Dans un système utilisant des objets dont les types sont inconnus jusqu'à l'exécution (services Web, appels distants, bases de données, flux, etc.), une exigence courante consiste à déterminer si une valeur null peut être affectée à l'objet ou si l'objet peut contenir un nul. La réalisation de telles opérations sur des types non annulables entraînera 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 d'éviter proactivement de tels problèmes, il est nécessaire de déterminer si un objet de type arbitraire est capable de contenir un null; c'est-à-dire s'il est généralement «annulable».
Dans un sens très pratique et typique, la nullité en termes .NET n'implique pas du tout nécessairement que le Type d'un objet est une forme de Nullable. Dans de nombreux cas, en fait, les objets ont des types de référence, peuvent contenir une valeur nulle et sont donc tous nullables; aucun d'entre eux n'a un type Nullable. Par conséquent, à des fins pratiques dans la plupart des scénarios, des tests doivent être effectués pour le concept général de nullité, par rapport au concept dépendant de l'implémentation de Nullable. Nous ne devons donc pas nous arrêter en nous concentrant uniquement sur le type .NET Nullable, mais plutôt intégrer notre compréhension de ses exigences et de son comportement dans le processus de concentration sur le concept général et pratique de nullité.