2010-09-14 19 views
5

In C# Posso usare default(T) per ottenere il valore predefinito di un tipo. Devo ottenere il tipo predefinito in fase di esecuzione da un System.Type. Come posso fare questo?Come posso chiamare predefinito (T) con un tipo?

E.g. Qualcosa sulla falsariga di questo (che non funziona)

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

risposta

9

Per un tipo di riferimento restituire null, per un tipo di valore, è possibile provare a utilizzare Activator.CreateInstance o chiamare il costruttore predefinito del tipo.

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

    return null; 
} 
+1

Poco dopo aver scritto la mia domanda mi sono inventato 'return Expression. Lambda > (Expression.Convert (Expression.Default (type), typeof (object))). Compile()(); ', ma il tuo è molto più bello. – GiddyUpHorsey

+0

@Giddy: questo sarebbe un modo molto costoso per farlo, dal momento che stai compilando l'albero delle espressioni in IL (e poi JIT dovrà compilarlo in nativo) ad ogni invocazione. –

+0

Sì, sono d'accordo. Questo è il motivo per cui non lo sto usando e sto usando la soluzione di Madgnome. Anche se, è stato il codice più breve e più leggibile, non la performance, che mi ha spinto a usare la sua.Le prestazioni non sono troppo grandi per il mio scenario. – GiddyUpHorsey

6

Se stai cercando di costruire un albero di espressione, utilizzare Expression.Default:

Expression expression = Expression.Default(type); 

Un altro modo si potrebbe fare questo abbastanza facilmente potrebbe essere:

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

Brutto, ma sarà lavorare :) si noti che è difficile ottenere il valore di default di un tipo nullable, come sarà un essere sempre inserito in un riferimento nullo

Come notato nei commenti, ci sono alcuni scenari oscuri (void e tipi di puntatore), dove queste non sono equivalenti, ma sono casi d'angolo :)

+1

sto generando alberi di espressione per l'utilizzo con Mindscape Lightspeed, ma il loro fornitore di query non supporta 'DefaultExpression', quindi ho bisogno il valore effettivo di mettere all'interno di un' ConstantExpression'. – GiddyUpHorsey

+0

Il più lieve dei nitpickings, il behviour è diverso per i tipi di puntatore. 'default (int *)' restituisce 'IntPtr.Zero', mentre' Predefinito (typeof (int *)) 'gira. Un'altra area oscura che ho scoperto è per 'System.Void', non puoi fare' default (void) 'mentre' Default (typeof (void)) 'restituisce null. No biggie, nel caso in cui qualcuno vuole prendersi cura di .. – nawfal

+0

@nawfal: Aggiunta una nota in tal senso, grazie. –

3

Questo è abbastanza facile, basta avere 2 casi da considerare :

  • tipi di riferimento: il valore di default è sempre nullo
  • tipi di valore: si può facilmente creare un'istanza utilizzando Activator.CreateInstance

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

Si potrebbe anche considerare l'utilizzo di FormatterServices.GetUninitializedObject anziché Activator.CreateInstance, probabilmente è più veloce.

+0

Hai provato a eseguire il codice? Non funzionerà, e il motivo è che i tipi di valore non hanno (normalmente) un costruttore predefinito. Lo fanno in C#, ma è una finzione; a livello CLR non ce n'è, e 'initobj' è usato in IL. –

+0

@Pavel, hai ragione, non mi sono mai accorto che non c'era un vero costruttore predefinito ... L'ho cambiato in Activator.CreateInstance, e funziona bene –

Problemi correlati