Equivalente programático de default (Type)

Eu estou usando reflection para percorrer as propriedades de um Type e definir certos tipos para seu padrão. Agora, eu poderia fazer um switch no tipo e definir o default(Type) explicitamente, mas eu prefiro fazê-lo em uma linha. Existe um equivalente programático de padrão?

    • No caso de um tipo de valor, use Activator.CreateInstance e ele deve funcionar bem.
    • Ao usar o tipo de referência, apenas retorne null
     public static object GetDefault(Type type) { if(type.IsValueType) { return Activator.CreateInstance(type); } return null; } 

    Na versão mais recente do .net, como padrão .net, type.IsValueType precisa ser escrito como type.GetTypeInfo().IsValueType

    Por que não chamar o método que retorna o padrão (T) com reflection? Você pode usar GetDefault de qualquer tipo com:

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

    Você pode usar PropertyInfo.SetValue(obj, null) . Se chamado em um tipo de valor, ele fornecerá o padrão. Esse comportamento está documentado no .NET 4.0 e no .NET 4.5 .

    Se você estiver usando o .NET 4.0 ou superior e quiser uma versão programática que não seja uma codificação de regras definidas fora do código , você pode criar uma Expression , compilá-la e executá-la on-the-fly.

    O método de extensão a seguir levará um Type e obterá o valor retornado do default(T) por meio do método Default na class Expression :

     public static T GetDefaultValue() { // We want an Func which returns the default. // Create that expression here. Expression> e = Expression.Lambda>( // 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 which returns the default. // Create that expression here. Expression> e = Expression.Lambda>( // 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()(); } 

    Você também deve armazenar em cache o valor acima com base no Type , mas esteja ciente de que, se estiver chamando isso para um grande número de instâncias Type e não usá-lo constantemente, a memory consumida pelo cache poderá superar os benefícios.

    Por que você diz que os genéricos estão fora de cena?

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

    Esta é a solução otimizada da 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 typeDefaults = new ConcurrentDictionary(); public static object GetDefaultValue(this Type type) { return type.IsValueType ? typeDefaults.GetOrAdd(type, Activator.CreateInstance) : null; } } } 

    A resposta escolhida é uma boa resposta, mas tenha cuidado com o object retornado.

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

    Extrapolando …

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

    As expressões podem ajudar aqui:

      private static Dictionary lambdasMap = new Dictionary(); 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(); } 

    Eu não testei este snippet, mas acho que deveria produzir nulos “tipados” para tipos de referência.

    Ainda não consigo encontrar nada simples e elegante, mas tenho uma idéia: se você souber o tipo de propriedade que deseja definir, poderá escrever seu próprio default(T) . Existem dois casos – T é um tipo de valor e T é um tipo de referência. Você pode ver isso, verificando T.IsValueType . Se T é um tipo de referência, você pode simplesmente defini-lo como null . Se T for um tipo de valor, ele terá um construtor sem parâmetros padrão para o qual você pode chamar para obter um valor “em branco”.

    Eu faço a mesma tarefa assim.

     //in MessageHeader private void SetValuesDefault() { MessageHeader header = this; Framework.ObjectPropertyHelper.SetPropertiesToDefault(this); } //in ObjectPropertyHelper public static void SetPropertiesToDefault(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; } 

    Equivalente à resposta de Dror, mas como um método de extensão:

     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; } } } 
      ///  /// returns the default value of a specified type ///  ///  public static object GetDefault(this Type type) { return type.IsValueType ? (!type.IsGenericType ? Activator.CreateInstance(type) : type.GenericTypeArguments[0].GetDefault() ) : null; }