2011-01-13 14 views
78

Vorrei verificare se un tipo noto in fase di esecuzione fornisce un costruttore senza parametri. La classe Type non ha dato risultati promettenti, quindi presumo di dover utilizzare la riflessione?Come posso verificare se un tipo fornisce un costruttore senza parametri?

+0

Penso che sia giusto – kenny

+2

Sidenote: C'è un vincolo generico per i costruttori senza parametri. – CodesInChaos

+1

è la domanda se il tipo ** solo ** fornisce un costruttore senza parametri o se ne fornisce uno a tutti? – BrokenGlass

risposta

132

Il Type classe è riflessione. Si può fare:

Type theType = myobject.GetType(); // if you have an instance 
// or 
Type theType = typeof(MyObject); // if you know the type 

var constructor = theType.GetConstructor(Type.EmptyTypes); 

Restituirà null se non esiste un costruttore senza parametri.


Se anche voi volete trovare costruttori privati, utilizzare il leggermente più lungo:

var constructor = theType.GetConstructor(
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, 
    null, Type.EmptyTypes, null); 

C'è un avvertimento per i tipi di valore, che aren't allowed to have a default constructor. È possibile verificare se si dispone di un tipo di valore utilizzando la proprietà Type.IsValueType e creare istanze utilizzando Activator.CreateInstance(Type);

+2

questo non troverà cori privati ​​fyi –

+2

Questo non funzionerà anche per i tipi di valore. – leppie

+2

Commenti indirizzati sopra. –

12

Sì, è necessario utilizzare Reflection. Ma fai già che quando si utilizza GetType()

Qualcosa di simile:

var t = x.GetType(); 
var c = t.GetConstructor(new Type[0]); 
if (c != null) ... 
6

Questo dovrebbe funzionare:

myClass.GetType().GetConstructors() 
        .All(c=>c.GetParameters().Length == 0) 
+1

Non è quello che intendevo, ma per favore non cancellarlo - è un problema correlato e una bella informazione. – mafu

1

Sì, è necessario utilizzare la riflessione.

object myObject = new MyType(); 
Type type = myObject.GetType(); 
ConstructorInfo conInfo = type.GetConstructor(new Type[0]); 
3

A seconda della situazione, si potrebbe anche usare una restrizione tipo generico:

public void DoSomethingWith<T>(T myObject) where T:new() {...} 

La dichiarazione di metodo di cui sopra sarà limitare il tipo di parametro a qualsiasi oggetto che può essere istanziato con un costruttore senza parametri. Il vantaggio qui è che il compilatore prenderà qualsiasi tentativo di usare il metodo con una classe che non ha un costruttore senza parametri, quindi finché il tipo è conosciuto SOMEWHERE in fase di compilazione, funzionerà e ti avviserà di un problema in precedenza.

Ovviamente se il tipo è noto solo in fase di esecuzione (ad esempio, si sta utilizzando Activator.CreateInstance() per creare un'istanza di un oggetto in base a una stringa o un tipo costruito), questo non sarà di aiuto. Generalmente uso la riflessione come ultima opzione assoluta, perché una volta che sei passato alla terra dinamica devi praticamente rimanere in una terra dinamica; di solito è difficile o anche più disordinato creare un'istanza dinamicamente e poi iniziare a gestirlo staticamente.

+0

In realtà, esiste un modello molto utile per eseguire il bridging delle terre di invocazione statica e dinamica: una classe di caching generica statica [ad es. 'EqualityComparer.Default ']. Per ogni dato tipo 'T', si dovrà usare Reflection una volta sola per costruire un oggetto il cui tipo di istanza sarà staticamente noto per qualificarsi per qualsiasi vincolo richiesto, e memorizzare un riferimento ad esso in un campo che non impone alcun vincolo che un chiamante potrebbe non essere in grado di fornire. – supercat

10
type.GetConstructor(Type.EmptyTypes) != null 

non riuscirebbe per struct s. Meglio di estenderlo:

public static bool HasDefaultConstructor(this Type t) 
{ 
    return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null; 
} 

riesce dal momento che anche enum s hanno costruttore senza parametri di default. Accelera leggermente anche per i tipi di valore poiché la chiamata di riflessione non viene eseguita.

1

Avevo bisogno di contare i costruttori con solo i parametri opzionali come i veri costruttori senza parametri.Per fare ciò:

myClass.GetType().GetConstructors() 
    .All(c => c.GetParameters().Length == 0 || c.GetParameters().All(p => p.IsOptional)) 
Problemi correlati