2009-08-18 19 views
5

ver que tengo una situación como esta ...Pass Tipo de forma dinámica a <T>

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

ahora tengo un método genérico que crea un objeto XML de List<T> - Algo como esto ..

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 
    } 
} 

Ahora con el fin de ejecutar este método que tengo que hacer como esto:

string xml = GetXML<Roles>(myRoledata); 

Ahora no sé qué Type puede venir a mí para pasar al método GetXML. Tengo un método que llamará al GetXML para diferentes Type s p. Ej. Roles, Users etc

Ahora puedo conseguir el Type dentro del List<> como esto

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

, pero no puede pasar como este

string xml = GetXML<genericType>(myRoledata); 

¿Hay alguna forma en la que yo pueda pasar cualquier genericTypes a GetXML método?

+0

Es probable que desee dejar en claro en la pregunta si los tipos (posiblemente múltiples) de T son desconocidos en tiempo de compilación o no. Si se conocen, la respuesta de Ulrik tiene sentido, es decir, dejar de transmitir y forzar el tipo de argumento (quizás con varias sobrecargas). Si no se conoce, debe usar el reflejo, de alguna forma, y ​​la respuesta de Marcas muestra la mejor y más simple forma de lograr esto. – ShuggyCoUk

Respuesta

2

Este es un problema que probablemente desee evitar resolver. Es es posible, a través de la reflexión, para llamar a los métodos dinámicamente sin resolverlos estáticamente, pero de alguna manera vence el punto de las anotaciones de tipo.

Cualquiera de hacer esto:

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

... lo que ahora se puede llamar con cualquier IEnumerable, o escribir la forma "moderna" como:

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

... lo que sea posible llame con cualquier IEnumerable a través de GetXML(someEnumerable.Cast<object>()) y en C# 4.0, incluso directamente por covarianza.

Si necesita el tipo de un tiempo de ejecución elemento, lo puede conseguir usando .GetType() en cada elemento, o simplemente puede pasar como parámetro (y proporcionar un reemplazo para compatibilidad con versiones anteriores):

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>()); 
} 

Por cierto, si está construyendo XML, una cadena es probablemente una opción de tipo de retorno menos robusta: de ser posible, podría trabajar con algo como un XElement en su lugar, y obtener la garantía de validez xml para arrancar.

+0

En realidad, desaconsejaría usar 'IEnumerable ' directamente, al menos hasta C# 4.0; es probable que no haga lo que usted quiere, debido a la falta de variación en los parámetros de tipo. 'IEnumerable' es más que utilizable. –

+0

Bueno, específicamente para IEnumerable, la covarianza es un problema menor debido al operador '.Cast <>' de Linq. Si desea llamar a un método con un parámetro 'IEnumerable ' y tiene un 'IEnumerable myEnum' con algún' T! = Object', puede hacer 'myEnum.Cast ()' con poca pérdida de legibilidad y velocidad. La desventaja estilística del 'IEnumerable' no genérico es la falta de soporte explícito de 'IDisposable', el hecho de que' System.Collections' no está en el conjunto predeterminado de usos que VS.NET agrega a los archivos nuevos, y que es un lenguaje menos común. –

+0

En cualquier caso, gracias por el comentario: "IEnumerable" no genérico también es una buena elección. –

7

Para hacer eso, necesita usar la reflexión;

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

donde inst es null si es un método estático, this para la instancia actual (en cuyo caso también se puede utilizar GetType() en lugar de typeof(SomeClass)), o el objeto de destino de otra manera.

+2

¿Pero no es esto fundamentalmente erróneo? Al invocar el método de esta manera, realmente no hay ninguna razón para usar genéricos en absoluto, porque descarta las comprobaciones de tipo y obtiene todos sus errores en tiempo de ejecución. –

+1

Mi interpretación de la pregunta es que querían desacoplarla de los genéricos. Si esa interpretación es incorrecta, entonces su enfoque es claramente más apropiado. Depende del escenario ;-p –

7

Desde emitir su parámetro ListData como una lista < T> en la primera línea de su método, ¿por qué no acaba de cambiar la firma del método a

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

De esta manera, usted no tiene usar la reflexión para obtener los argumentos genéricos.

EDIT: Veo que debe ser capaz de aceptar colecciones IEnumerable, y no solo listas. Por lo tanto, considere cambiar su firma de método a

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

Tiene la idea correcta, pero está utilizando el método equivocado. Eche un vistazo a Type.MakeGenericType o MethodInfo.MakeGenericMethod. Tomará algunas líneas más que tu ejemplo, pero debería ser simple de resolver.

GetGenericArguments() se puede utilizar para obtener el tipo Roles de una lista. Es la forma diferente alrededor.

Btw: parece que está implementando algún tipo de serialización XML. Asegúrese de verificar las clases existentes, antes de reinventar la rueda.;-)

2

No sé su situación, pero ¿es posible reescribir su función como:

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

Entonces se le puede llamar como se:

List<Role> myList; 
GetXML(myList); 

Puede añadir tipo parámetros tan atrás como sea necesario para soportarlo, hasta que llegue a un lugar que sí sabe qué es el tipo sólido.

Cuestiones relacionadas