Question Équivalent programmatique de défaut (Type)


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


440
2017-11-28 10:11


origine


Réponses:


  • Dans le cas d'une utilisation de type valeur Activator.CreateInstance et ça devrait bien marcher.
  • Lorsque vous utilisez le type de référence, renvoyez simplement null
public static object GetDefault(Type type)
{
   if(type.IsValueType)
   {
      return Activator.CreateInstance(type);
   }
   return null;
}

Dans la nouvelle version de .net telle que .net standard, type.IsValueType doit être écrit comme type.GetTypeInfo().IsValueType


594
2017-12-09 15:14



Pourquoi ne pas appeler la méthode qui renvoie default (T) avec 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);
    }

89
2017-11-05 19:24



Vous pouvez utiliser PropertyInfo.SetValue(obj, null). Si vous êtes appelé sur un type de valeur, cela vous donnera la valeur par défaut. Ce comportement est documenté dans .NET 4.0 et dans .NET 4.5.


75
2018-04-23 21:48



Si vous utilisez .NET 4.0 ou supérieur et que vous voulez une version programmatique qui n'est pas une codification de règles définies en dehors du code, vous pouvez créer un Expression, compilez et exécutez-le à la volée.

La méthode d'extension suivante prendra une Type et obtenir la valeur retournée de 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 en fonction du Type, mais soyez conscient si vous appelez cela pour un grand nombre de Type Dans certains cas, et ne l'utilisez pas constamment, la mémoire consommée par le cache risque de dépasser les avantages.


52
2017-10-04 18:24



Pourquoi dites-vous que les génériques sont hors de l'image?

    public static object GetDefault(Type t)
    {
        Func<object> f = GetDefault<object>;
        return f.Method.GetGenericMethodDefinition().MakeGenericMethod(t).Invoke(null, null);
    }

    private static T GetDefault<T>()
    {
        return default(T);
    }

34
2017-10-26 20:47



Ceci 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;
        }
    }
}

21
2017-11-14 10:00



La réponse choisie est une bonne réponse, mais soyez prudent avec l'objet retourné.

string test = null;
string test2 = "";
if (test is string)
     Console.WriteLine("This will never be hit.");
if (test2 is string)
     Console.WriteLine("Always hit.");

Extrapoler ...

string test = GetDefault(typeof(string));
if (test is string)
     Console.WriteLine("This will never be hit.");

7
2017-10-16 19:30



Les expressions peuvent aider ici:

    private static Dictionary<Type, Delegate> lambdasMap = new Dictionary<Type, Delegate>();

    private object GetTypedNull(Type type)
    {
        Delegate func;
        if (!lambdasMap.TryGetValue(type, out func))
        {
            var body = Expression.Default(type);
            var lambda = Expression.Lambda(body);
            func = lambda.Compile();
            lambdasMap[type] = func;
        }
        return func.DynamicInvoke();
    }

Je n'ai pas testé cet extrait, mais je pense qu'il devrait produire des "null" typés pour les types de référence.


5
2017-12-26 00:15



Je ne trouve rien de simple et d'élégant pour l'instant, mais j'ai une idée: si vous connaissez le type de propriété que vous souhaitez définir, vous pouvez écrire votre propre default(T). Il y a deux cas - T est un type de valeur et T est un type de référence. Vous pouvez voir cela en vérifiant T.IsValueType. Si T est un type de référence, vous pouvez simplement le définir sur null. Si T est un type de valeur, alors il aura un constructeur par défaut sans paramètre que vous pouvez appeler pour obtenir une valeur "vide".


4
2017-11-28 10:30



Je fais la même tâche comme ça.

//in MessageHeader 
   private void SetValuesDefault()
   {
        MessageHeader header = this;             
        Framework.ObjectPropertyHelper.SetPropertiesToDefault<MessageHeader>(this);
   }

//in ObjectPropertyHelper
   public static void SetPropertiesToDefault<T>(T obj) 
   {
            Type objectType = typeof(T);

            System.Reflection.PropertyInfo [] props = objectType.GetProperties();

            foreach (System.Reflection.PropertyInfo property in props)
            {
                if (property.CanWrite)
                {
                    string propertyName = property.Name;
                    Type propertyType = property.PropertyType;

                    object value = TypeHelper.DefaultForType(propertyType);
                    property.SetValue(obj, value, null);
                }
            }
    }

//in TypeHelper
    public static object DefaultForType(Type targetType)
    {
        return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
    }

3
2017-11-28 11:18



Équivalent à la réponse de Dror mais en tant que méthode d'extension:

namespace System
{
    public static class TypeExtensions
    {
        public static object Default(this Type type)
        {
            object output = null;

            if (type.IsValueType)
            {
                output = Activator.CreateInstance(type);
            }

            return output;
        }
    }
}

2
2018-06-26 15:48