2010-09-14 17 views
5

En C# Puedo usar default(T) para obtener el valor predeterminado de un tipo. Necesito obtener el tipo predeterminado en tiempo de ejecución desde System.Type. ¿Cómo puedo hacer esto?¿Cómo puedo llamar al valor predeterminado (T) con un tipo?

E.g. Algo a lo largo de las líneas de este (que no funciona)

var type = typeof(int); 
var defaultValue = default(type); 

Respuesta

9

Para un tipo de referencia return null, para un tipo de valor, puede intentar usar Activator.CreateInstance o llamar al constructor predeterminado del tipo.

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

    return null; 
} 
+1

Poco después de escribir mi pregunta, se me ocurrió 'return Expression. Lambda > (Expression.Convert (Expression.Default (type), typeof (object))). Compile()(); ', pero el tuyo es mucho más agradable. – GiddyUpHorsey

+0

@Giddy: esa sería una forma muy costosa de hacerlo, ya que estás compilando el árbol de expresiones en IL (y luego JIT tendrá que compilarlo en nativo) en cada invocación. –

+0

Sí, estoy de acuerdo. Por eso no lo estoy usando, y estoy usando la solución de Madgnome en su lugar. Sin embargo, fue el código más corto y más legible, no el rendimiento, lo que me empujó a utilizar el suyo.El rendimiento no es demasiado importante para mi escenario. – GiddyUpHorsey

6

Si usted está tratando de construir un árbol de expresión, utilice Expression.Default:

Expression expression = Expression.Default(type); 

Otra forma en que podría hacer esto con bastante facilidad sería:

object defaultValue = Array.CreateInstance(type, 1).GetValue(0); 

feo, pero va a trabajar :) Tenga en cuenta que es difícil obtener el valor por defecto de un tipo anulable, como lo hará una Siempre estará en caja a una referencia nula.

Como se señaló en los comentarios, hay algunos escenarios oscuros (void y tipos de puntero) siempre que éstas no son equivalentes, pero son casos de esquina :)

+1

estoy generar árboles de expresión para su uso con Mindscape Lightspeed, pero su proveedor de consulta no admite 'DefaultExpression', así que necesito el valor real para poner dentro de un' ConstantExpression'. – GiddyUpHorsey

+0

La más leve de las pequeñas nimiedades, el comportamiento es diferente para los tipos de puntero. 'default (int *)' devuelve 'IntPtr.Zero', mientras' Default (typeof (int *)) 'arroja. Otro área oscura que he descubierto es 'System.Void', no se puede hacer' default (void) 'mientras que' Default (typeof (void)) 'devuelve null. No hay problema, solo en caso de que alguien quiera ocuparse de ... – nawfal

+0

@nawfal: Agregué una nota al respecto, gracias. –

3

Eso es bastante fácil, sólo hay 2 casos a considerar :

  • tipos de referencia: el valor por defecto es siempre nulos
  • tipos de valor: usted puede crear fácilmente una instancia utilizando Activator.CreateInstance

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

También podría considerar el uso FormatterServices.GetUninitializedObject en lugar de Activator.CreateInstance, es probablemente más rápido.

+0

¿Has intentado ejecutar tu código? No funcionará, y la razón es que los tipos de valores no tienen (normalmente) un constructor predeterminado. Lo hacen en C#, pero es una ficción; en el nivel CLR no hay ninguno, y 'initobj' se usa en IL. –

+0

@Pavel, tienes razón, nunca me di cuenta de que no había un constructor predeterminado real ... Lo cambié a Activator.CreateInstance, y funciona bien –

Cuestiones relacionadas