2009-08-18 15 views
5

vedere ho una situazione come questa ...Pass Tipo dinamicamente per <T>

object myRoledata = List<Roles>() --> (some list or Ienumerable type) 

Ora ho un metodo generico che crea un oggetto XML da List<T> - Qualcosa di simile ..

public string GetXML<T>(object listdata) 
{ 
    List<T> objLists = (List<T>)Convert.ChangeType(listData, typeof(List<T>)); 
    foreach(var obj in listdata) 
    { 
     //logic to create xml 
    } 
} 

Ora, al fine di eseguire questo metodo che devo fare in questo modo:

string xml = GetXML<Roles>(myRoledata); 

Ora non so cosa mi può passare Type da passare al metodo GetXML. Ho un metodo che chiamerà GetXML per diversi Type s per es. Roles, Users ecc

ora posso ottenere il Type all'interno del List<> come questo

Type genericType = obj.GetType().GetGenericArguments()[0]; 

ma non può passare in questo modo

string xml = GetXML<genericType>(myRoledata); 

C'e 'qualche cosa in cui posso passare qualsiasi genericTypes a Metodo GetXML?

+0

Probabilmente vorrete chiarire nella domanda se i (possibilmente multipli) tipi di T sono sconosciuti al momento della compilazione o meno. Se sono conosciuti, la risposta di Ulrik ha senso, cioè smetti di lanciare e forza il tipo di argomento (magari con diversi sovraccarichi). Se non è noto, è necessario utilizzare la riflessione, in qualche modo, e la risposta di Marks mostra il modo più semplice e probabilmente migliore per raggiungere questo obiettivo. – ShuggyCoUk

risposta

2

Questo è un problema che probabilmente si desidera risolvere . È è possibile, tramite riflessione, chiamare i metodi dinamicamente senza risolverli staticamente - ma in qualche modo sconfigge l'intero punto delle annotazioni tipo.

O fare questo:

public string GetXML(IEnumerable listdata) { 
    foreach(object obj in listdata) 
     //logic to create xml 
} 

... quale è ora possibile chiamare con qualsiasi IEnumerable, o scrivere nel modo "moderno" come:

public string GetXML(IEnumerable<object> listdata) { 
    foreach(object obj in listdata) 
     //logic to create xml 
} 

... che si può chiamare con qualsiasi IEnumerable tramite GetXML(someEnumerable.Cast<object>()) e in C# 4.0 anche direttamente dalla covarianza.

Se è necessario il tipo di un runtime elemento, si può ottenere usando .GetType() su ogni elemento, oppure si può semplicemente passare come parametro (e di fornire un override per retrocompatibilità):

public string GetXML(Type elementType, IEnumerable<object> listdata) { 
    foreach(object obj in listdata) 
     //logic to create xml 
} 

public string GetXML<T>(IEnumerable<T> listdata) { 
    return GetXML(typeof(T),listdata.Cast<object>()); 
} 

Per inciso, se stai costruendo XML, una stringa è probabilmente una scelta meno affidabile di tipo di ritorno: se possibile, potresti lavorare con qualcosa come un XElement invece - e ottenere la garanzia di validità xml per l'avvio.

+0

In realtà, sconsiglio di usare 'IEnumerable ' direttamente, fino a C# 4.0; probabilmente non farà quello che vuoi, a causa della mancanza di varianza nei parametri di tipo. 'IEnumerable' è più che utilizzabile. –

+0

Bene, in particolare per IEnumerable, la covarianza è un problema minore a causa dell'operatore Linq '.Cast <>'. Se si desidera chiamare un metodo con un parametro 'IEnumerable ' e si dispone di un 'IEnumerable myEnum' con alcuni' T! = Object', si può semplicemente fare 'myEnum.Cast ()' con poca perdita di leggibilità e velocità. Lo svantaggio stilistico del non generico 'IEnumerable' è la mancanza del supporto esplicito' IDisposable', il fatto che 'System.Collections' non sia nel set predefinito di ustion che VS.NET aggiunge ai nuovi file, e che sia un idioma meno comune. –

+0

In ogni caso, grazie per il commento - non generico 'IEnumerable' è una buona scelta. –

7

Per fare ciò, è necessario utilizzare la riflessione;

typeof(SomeClass).GetMethod("GetXML").MakeGenericMethod(genericType) 
     .Invoke(inst, new object[] {myRoleData}); 

dove inst è null se è un metodo statico, this per l'istanza corrente (in questo caso è possibile anche utilizzare GetType() anziché typeof(SomeClass)), oppure l'oggetto bersaglio altrimenti.

+2

Ma questo non è fondamentalmente sbagliato? Invocando il metodo in questo modo, non c'è davvero alcun motivo per utilizzare i generici, perché si eliminano i controlli di tipo e si ottengono tutti gli errori in fase di esecuzione. –

+1

La mia interpretazione della domanda è che volevano separarlo dai generici. Se questa interpretazione non è corretta, il tuo approccio è chiaramente più appropriato. Dipende dallo scenario ;-p –

7

Dal momento che lanci la tua parametro ListData come un elenco < T> nella prima riga del metodo, perché non basta cambiare la firma del metodo per

public string GetXML<T>(List<T> listdata) 

In questo modo, non è necessario usare la riflessione per ottenere gli argomenti generici.

MODIFICA: vedo che è necessario poter accettare raccolte IEnumerable e non solo elenchi. Quindi, considera la possibilità di modificare la firma del metodo in

public string GetXML<T>(IEnumerable<T> listdata) 
0

Hai l'idea giusta, ma stai utilizzando il metodo sbagliato. Dai un'occhiata a Type.MakeGenericType o MethodInfo.MakeGenericMethod. Ci vorranno poche righe in più del tuo esempio, ma dovrebbe essere semplice da risolvere.

È possibile utilizzare GetGenericArguments() per ottenere il tipo di ruolo da un elenco. È il modo diverso in giro.

Btw: Sembra che tu abbia implementato una sorta di serializzazione XML. Assicurati di controllare le classi esistenti, prima di reinventare la ruota.;-)

2

Non so la vostra situazione, ma è possibile riscrivere la funzione come:

public string GetXML<T>(IEnumerable<T> listdata) 
{ 
    foreach(var obj in listdata) 
    { 
     //logic to create xml 
    } 
} 

allora può essere chiamato come:

List<Role> myList; 
GetXML(myList); 

È possibile aggiungere tipo parametri necessari per supportarlo, fino a quando non si arriva a un punto in cui non si conosce il tipo di solido.

Problemi correlati