2010-04-09 21 views
9

Ho un metodo come il seguente:C# Passo Generics a tempo di esecuzione

public IEnumerable<T> GetControls<T>() 
: where T : ControlBase 
{ 
// removed. 
} 

Poi ho creato una classe:

public class HandleBase<TOwner> : ControlBase 
: TOwner 
{ 
// Removed 
} 

Mi piacerebbe essere in grado di chiamare

GetControls<HandleBase<this.GetType()>>; 

dove dovrebbe utilizzare il tipo di questa classe per passare a HandleBase. Questo in sostanza otterrebbe tutti i HandleBase che hanno un proprietario di questo tipo.

Come posso ottenere questo risultato?

EDIT:

sto usando .NET 2.0 in modo da soluzioni superiori a 2.0 non funzioneranno.

L'idea è che ControlBase abbia una raccolta di altri ControlBase per "bambini". Quindi possono essere interrogati in base al loro tipo con GetControls<T>(). Questo mi permetterebbe, ad esempio, di ottenere tutto il HandleBase per una forma. Quindi posso prendere tutti questi e impostare Visible = false o fare qualcos'altro con loro. Così posso manipolare i bambini di un tipo specifico per una collezione.

HandleBase<TOwner> richiede il TOwner poiché ha un riferimento al "tipo proprietario". Quindi puoi solo aggiungere qualcosa che estende HandleBase a una forma. Ha senso?

Grazie per tutto l'aiuto!

+2

@TheCloudlessSky, perché invocare 'this.GetType()'? se stai invocando 'GetControls >();' da una classe basata sull'istanza [come 'this this' indica], perché non utilizzare semplicemente il nome tipo dichiarato della classe di implementazione? se questa è una classe base, ci sono mezzi per esporre il tipo della sottoclasse alla classe base. –

+0

Vedi modifica sopra. – TheCloudlessSky

risposta

0

questo è specifico per la mia realizzazione di questo, ma sono stato in grado di risolvere questo creando una non generica HandleBase e poi un generico HandleBase<TOwner> poiché l'unico posto Il proprietario era il proprietario.

Quindi quando posso chiamare GetControls<HandleBase> e ottenere tutto il HandleBase indipendentemente dal proprietario.

Grazie a tutti per le risposte!

2

Non è possibile. Generics è una funzionalità in fase di compilazione. Dovresti includere il tipo come parametro non generico per il metodo e passarlo lì.

+1

È possibile utilizzare la riflessione per farlo. Ma sembra davvero eccessivo per ciò che è descritto nel problema. Sono d'accordo con il passare il riferimento di tipo alla funzione invece. –

+0

System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly(); Digitare t = a.GetType ("SeaSharpWinApp8.Program"); MethodInfo mi = t.GetMethod ("f", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo miGeneric = mi.MakeGenericMethod (new Type [] {typeof (string)}); miGeneric.Invoke (null, new object [] {"works"}); –

+0

È la chiamata a MakeGenericMethod che ti consente di farlo. È necessario prima ottenere MethodInfo, quindi ottenere un altro con i tipi specifici che si desidera utilizzare. Se si tratta di un tipo generico, si effettua invece la chiamata MakeGeneric * al livello di tipo. –

13

È possibile eseguire questa operazione specificando un tipo in fase di compilazione o utilizzando la riflessione.

Puoi farlo con la riflessione in questo modo:

typeof(SomeClass).GetMethod("GetControls") 
    .MakeGenericMethod(typeof(HandleBase<>).MakeGenericType(GetType())) 
    .Invoke(someObject, null); 

Nota che sarebbe restituire un object; non saresti in grado di trasmetterlo a IEnumerable<T> (A meno che tu non sappia cosa sia T in fase di compilazione, nel qual caso non c'è alcun punto). Potresti trasmettere a IEnumerable.

Tuttavia, questa è una cattiva idea.
Probabilmente c'è una soluzione migliore per te; si prega di fornire maggiori dettagli.

+0

è possibile utilizzare la riflessione? ** Come? ** – serhio

+3

Questo è possibile usando il reflection, chiamando 'typeof (SomeClass) .GetMethod (" GetControls "). MakeGenericMethod (typeof (HandleBase <>). MakeGenericType (GetType())). Invoke (someObject, null) ' – SLaks

+0

Perché è stato downvoted? – SLaks

1

Si noti che i parametri di tipo non sono variabili. Pertanto, non è possibile utilizzare una variabile al posto di un parametro di tipo.

Si potrebbe, tuttavia, esegue questa operazione attraverso la riflessione, o utilizzando un costrutto speciale che è piuttosto limitata, ma potrebbe risolvere il caso:

public class MyClass<TSelf> where TSelf: MyClass<TSelf> { 
    public IEnumerable<T> GetControls<T>() where T: ControlBase { 
    // removed. 
    } 

    public void MyCall() { 
     GetControls<HandleBase<TSelf>>(); 
    } 
} 

public class MyConcreteClass: MyClass<MyConcreteClass> { 
} 
0

Probabilmente non c'è modo di fare quello che chiedete. Estendi il tuo esempio:

X x = GetControls<HandleBase<this.GetType()>>; 

Che tipo di X dovrebbe essere qui? Tuttavia da altre informazioni di base sembra che sia necessario ottenere l'elenco di tutti i controlli di un determinato tipo.Si potrebbe fare questo per esempio in tal modo:

public IEnumerable<ControlBase> GetControls(Type type) { 
//your logic here 
} 

A seconda delle altri usi e gli obiettivi si potrebbe anche voler tornare non generica IEnumerable.

0

Dal GetControls() restituisce un'enumerazione, si potrebbe trovare un modo per filtrare l'enumerazione risultante con .OfType <T>, qualcosa come

List<T2> list = controlList.GetControls<T>().OfType<T2>().ToList(); 

Si avrebbe bisogno di un vincolo generico somehwere lungo le linee di

where T2 : T 
+0

Questo è specifico per> = 3.0, ho dimenticato di menzionare che sto usando 2.0. – TheCloudlessSky