598 votes

Équivalent programmatique du défaut (Type)

J'utilise la réflexion pour boucler un Type et de définir certains types à leur valeur par défaut. Maintenant, je pourrais faire un switch sur le type et mettre la propriété default(Type) explicitement, mais je préfère le faire en une seule ligne. Existe-t-il un équivalent programmatique de default ?

0 votes

Cela devrait fonctionner : Nullable<T> a = new Nullable<T>().GetValueOrDefault() ;

809voto

Dror Helper Points 15499
  • Dans le cas d'un type de valeur, utilisez Activator.CreateInstance et ça devrait fonctionner correctement.
  • Lorsque vous utilisez un type de référence, il suffit de renvoyer null

    public static object GetDefault(Type type) { if(type.IsValueType) { return Activator.CreateInstance(type); } return null; }

Dans les nouvelles versions de .net telles que .net standard, type.IsValueType doit être écrit comme suit type.GetTypeInfo().IsValueType

24 votes

Ceci retournera un type de valeur encadré et n'est donc pas l'équivalent exact de default(Type). Cependant, il est aussi proche que vous allez obtenir sans génériques.

9 votes

Et alors ? Si vous trouvez un type qui default(T) != (T)(object)default(T) && !(default(T) != default(T)) alors vous avez un argument, sinon cela n'a pas d'importance qu'il soit encadré ou non, puisqu'ils sont équivalents.

7 votes

La dernière partie du prédicat permet d'éviter de tricher avec la surcharge des opérateurs... on pourrait faire default(T) != default(T) retourne false, et c'est de la triche ! =)

117voto

drake7707 Points 796

Pourquoi ne pas appeler la méthode qui renvoie default(T) avec la réflexion ? Vous pouvez utiliser GetDefault de n'importe quel type avec :

    public object GetDefault(Type t)
    {
        return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(t).Invoke(this, null);
    }

    public T GetDefaultGeneric<T>()
    {
        return default(T);
    }

10 votes

C'est génial parce que c'est si simple. Bien que ce ne soit pas la meilleure solution, il est important de la garder à l'esprit car cette technique peut être utile dans de nombreuses circonstances similaires.

0 votes

Si vous appelez la méthode générique "GetDefault" à la place (surcharge), faites ceci : this.GetType().GetMethod("GetDefault", new Type[0]).<AS_IS>

0 votes

Let GetDefaultGeneric return object et vous êtes prêt à faire un peu de cache pour la vitesse.

98voto

JoelFan Points 11368

Vous pouvez utiliser PropertyInfo.SetValue(obj, null) . S'il est appelé sur un type de valeur, il vous donnera la valeur par défaut. Ce comportement est documenté dans .NET 4.0 y dans .NET 4.5 .

8 votes

Pour cette question spécifique - boucler les propriétés d'un type ET les définir comme "par défaut" - cela fonctionne parfaitement. Je l'utilise pour convertir un SqlDataReader en objet en utilisant la réflexion.

58voto

casperOne Points 49736

Si vous utilisez .NET 4.0 ou plus et que vous souhaitez une version programmatique qui ne soit pas une codification de règles définies en dehors du code vous pouvez créer un Expression de le compiler et de l'exécuter à la volée.

La méthode d'extension suivante prend un Type et obtenir la valeur retournée par default(T) à travers le Default méthode sur le Expression classe :

public static T GetDefaultValue<T>()
{
    // We want an Func<T> which returns the default.
    // Create that expression here.
    Expression<Func<T>> e = Expression.Lambda<Func<T>>(
        // The default value, always get what the *code* tells us.
        Expression.Default(typeof(T))
    );

    // Compile and return the value.
    return e.Compile()();
}

public static object GetDefaultValue(this Type type)
{
    // Validate parameters.
    if (type == null) throw new ArgumentNullException("type");

    // We want an Func<object> which returns the default.
    // Create that expression here.
    Expression<Func<object>> e = Expression.Lambda<Func<object>>(
        // Have to convert to object.
        Expression.Convert(
            // The default value, always get what the *code* tells us.
            Expression.Default(type), typeof(object)
        )
    );

    // Compile and return the value.
    return e.Compile()();
}

Vous devez également mettre en cache la valeur ci-dessus sur la base de l'adresse de l'utilisateur. Type mais attention, si vous l'appelez pour un grand nombre d'utilisateurs, vous ne pouvez pas l'utiliser. Type et ne l'utilisez pas en permanence, la mémoire consommée par le cache pourrait l'emporter sur les avantages.

6 votes

Performances pour "return type.IsValueType ? Activator.CreateInstance(type) : null;' est 1000x plus rapide que e.Compile()() ;

0 votes

@Cyrus Et pour une valeur qui est en cache ?

2 votes

@Cyrus je suis presque sûr que ce serait l'inverse si vous mettez en cache la e.Compile() . C'est là tout l'intérêt des expressions.

28voto

cuft Points 81

C'est la solution optimisée de Flem :

using System.Collections.Concurrent;

namespace System
{
    public static class TypeExtension
    {
        //a thread-safe way to hold default instances created at run-time
        private static ConcurrentDictionary<Type, object> typeDefaults =
           new ConcurrentDictionary<Type, object>();

        public static object GetDefaultValue(this Type type)
        {
            return type.IsValueType
               ? typeDefaults.GetOrAdd(type, Activator.CreateInstance)
               : null;
        }
    }
}

3 votes

Une version abrégée du retour : return type.IsValueType ? typeDefaults.GetOrAdd(type, Activator.CreateInstance) : null;

4 votes

Qu'en est-il des structs mutables ? Savez-vous qu'il est possible (et légal) de modifier les champs d'une struct boxée, de sorte que les données changent ?

0 votes

@IllidanS4 comme le nom de la méthode l'indique, cela ne concerne que les valeurs par défaut du ValueType.

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