73 votes

Comment convertir un System.Type pour sa version nullable ?

Encore une de celles-ci: "Existe-t-il une méthode de travail intégrée plus facile à la place de la 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<int> (which is the same)
if (t is primitive) then Nullable<T> else just T
 

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

105voto

Alex Lyman Points 7480

Voici le code que j'utilise:

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

Edit: Le code d'origine avait un bogue qui se comporterait de manière inattendue si type était lui-même un Nullable<T>

15voto

Mark Jones Points 738

J'ai un couple de méthodes que j'ai écrit dans ma bibliothèque utilitaire que j'ai beaucoup compté sur. La première est une méthode qui convertit n'importe quel Type correspondant à son Nullable<Type> formulaire:

    /// <summary>
    /// [ <c>public static Type GetNullableType(Type TypeToConvert)</c> ]
    /// <para></para>
    /// Convert any Type to its Nullable&lt;T&gt; form, if possible
    /// </summary>
    /// <param name="TypeToConvert">The Type to convert</param>
    /// <returns>
    /// The Nullable&lt;T&gt; converted from the original type, the original type if it was already nullable, or null 
    /// if either <paramref name="TypeToConvert"/> could not be converted or if it was null.
    /// </returns>
    /// <remarks>
    /// To qualify to be converted to a nullable form, <paramref name="TypeToConvert"/> must contain a non-nullable value 
    /// type other than System.Void.  Otherwise, this method will return a null.
    /// </remarks>
    /// <seealso cref="Nullable&lt;T&gt;"/>
    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<Type>
        if (TypeToConvert.IsValueType && TypeToConvert != typeof(void))
            return typeof(Nullable<>).MakeGenericType(TypeToConvert);

        // Done - no conversion
        return null;
    }

La deuxième méthode simplement des rapports de savoir si un Type donné est nullable. Cette méthode est appelée par la première et est utile séparément:

    /// <summary>
    /// [ <c>public static bool IsTypeNullable(Type TypeToTest)</c> ]
    /// <para></para>
    /// Reports whether a given Type is nullable (Nullable&lt; Type &gt;)
    /// </summary>
    /// <param name="TypeToTest">The Type to test</param>
    /// <returns>
    /// true = The given Type is a Nullable&lt; Type &gt;; false = The type is not nullable, or <paramref name="TypeToTest"/> 
    /// is null.
    /// </returns>
    /// <remarks>
    /// This method tests <paramref name="TypeToTest"/> and reports whether it is nullable (i.e. whether it is either a 
    /// reference type or a form of the generic Nullable&lt; T &gt; type).
    /// </remarks>
    /// <seealso cref="GetNullableType"/>
    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<T> 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<>);
    }

Le ci-dessus IsTypeNullable mise en œuvre fonctionne comme un champion de tous les temps, mais il est légèrement détaillé et lente dans sa dernière ligne de code. Le code suivant corps est le même que ci-dessus pour IsTypeNullable, à l'exception de 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<T> 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;

Profitez-en!

Marque

P. S. - a Propos de "la possibilité de valeur null"

Je dois répéter une déclaration au sujet de la possibilité de valeur null je l'ai fait dans un autre post, qui s'applique directement à aborder correctement cette rubrique. C'est, je crois que la discussion ne doit pas être la façon de vérifier si un objet est un générique de type Nullable, mais plutôt de savoir si on peut attribuer une valeur null à un objet de ce type. En d'autres termes, je pense que nous devrions être de déterminer si un objet est de type nullable, pas de savoir s'il accepte les valeurs null. La différence est dans la sémantique, à savoir les raisons pratiques de détermination de la valeur null, ce qui est généralement tout ce qui compte.

Dans un système à l'aide d'objets avec des types, éventuellement, inconnu jusqu'au moment de l'exécution (services web, les appels distants, bases de données, de flux rss, etc.), une exigence commune est de déterminer si une valeur null peut être attribuée à l'objet, ou si l'objet peut contenir une valeur null. L'exécution de ces opérations sur la non-types nullables sera susceptible de produire des erreurs, généralement des exceptions, qui sont très coûteux à la fois en termes de performance et les exigences du code. Pour prendre le très-approche privilégiée de manière proactive éviter de tels problèmes, il est nécessaire de déterminer si un objet d'un Type arbitraire est capable de contenir une valeur null; c'est à dire, si c'est de manière générale, "les valeurs null'.

Dans un très pratique et très typique du sens, de la valeur null dans .NET, n'a pas du tout nécessairement qu'un Type de l'objet est une forme de Nullable. Dans de nombreux cas en effet, les objets ont des types de référence, peut contenir une valeur null, et sont donc toutes les valeurs null; aucun d'entre eux ont un type Nullable. Par conséquent, pour des raisons pratiques, dans la plupart des scénarios, les essais doivent être effectués pour le concept général de la possibilité de valeur null, par rapport à la mise en œuvre dépendante de la notion de Nullable. Donc nous ne devrions pas être raccroché en se concentrant uniquement sur l' .NET type Nullable mais plutôt intégrer notre compréhension de ses besoins et le comportement dans le processus de se concentrer sur le général, le concept pratique de la possibilité de valeur null.

9voto

Thracx Points 76

Lyman réponse est excellente et m'a aidé, cependant, il y a un bug qui doit être corrigé.

Nullable.GetUnderlyingType(type) ne doit être appelé ssi le type n'est pas déjà un type Nullable. Sinon, il me semble, à tort, de retourner la valeur null lorsque le type de dérive du Système.RuntimeType (comme quand je passe dans typeof(Système d'.Int32) ). Le dessous de la version évite de devoir appeler les valeurs null.GetUnderlyingType(type) vérifie si le type est Nullable à la place.

Vous trouverez ci-dessous une ExtensionMethod version de cette méthode qui permettra de restituer immédiatement le type , sauf si c'est un ValueType ce 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 tout simplement de poster un commentaire à Lyman réponse parce que je suis nouveau et n'ont pas encore assez rep.)

2voto

ljs Points 16511

Il n'y a pas quelque chose de construit en, que je sache, l'int?, etc. est juste sucre syntaxique pour Nullable<T> et ne fait pas l'objet d'un traitement particulier au-delà. Il est particulièrement peu probable étant donné que vous tentez d'obtenir ce à partir du type d'informations d'un type donné. Généralement qu'il faut toujours quelques "rouler propre" code comme une donnée. Vous devez utiliser la Réflexion pour créer un nouveau type Nullable avec le paramètre de type de le type d'entrée.

Edit: les commentaires suggèrent effectivement Nullable<> est spécialement traités, et dans l'exécution de démarrage, comme expliqué dans cet article.

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