2008-11-21 28 views
27

¿Es posible declarar una instancia de un genérico sin saber el tipo en tiempo de diseño?Declarar una instancia de tipo genérico dinámicamente

Ejemplo:

Int i = 1; 
List<typeof(i)> list = new List<typeof(i)>(); 

donde el tipo de Podría ser cualquier cosa, en lugar de tener que hacer:

List<int> list = new List<int(); 

Respuesta

43

Si no sé el tipo de en tiempo de compilación, pero desea que el tipo real (es decir, no List<object>) y no estás en un método genérico/tipo con el parámetro de tipo apropiado, entonces usted tiene que utilizar la reflexión.

para hacer más sencillo el reflejo , A veces introduje un nuevo tipo o método genérico en mi propio código, así que puedo llamarlo por reflexión, pero el n solo use genéricos normales después de eso. Por ejemplo:

object x = GetObjectFromSomewhere(); 
// I want to create a List<?> containing the existing 
// object, but strongly typed to the "right" type depending 
// on the type of the value of x 
MethodInfo method = GetType().GetMethod("BuildListHelper"); 
method = method.MakeGenericMethod(new Type[] { x.GetType() }); 
object list = method.Invoke(this, new object[] { x }); 

// Later 

public IList<T> BuildListHelper<T>(T item) 
{ 
    List<T> list = new List<T>(); 
    list.Add(item); 
    return list; 
} 

Por supuesto, no se puede hacer un montón con la lista después si usted no sabe el tipo ... es por eso que este tipo de cosas a menudo cae hacia abajo. Sin embargo, no siempre - He usado algo como el anterior en algunas ocasiones, donde el sistema de tipos simplemente no me deja expresar todo lo que necesito de forma estática.

EDITAR: Tenga en cuenta que aunque estoy llamando a Type.GetMethod en el código anterior, si iba a ejecutarlo mucho, probablemente querría simplemente llamarlo una vez; después de todo, el método no funciona cambiar. Es posible que pueda hacerlo estático (podría hacerlo en el caso anterior) y probablemente también desee hacerlo privado. Lo dejé como un método de instancia pública para la simplicidad de la llamada a GetMethod en el código de muestra; de lo contrario, necesitaría especificar los indicadores de enlace apropiados.

+0

Puede devolver un IList no genérico (que es compatible con List <>), entonces la lista devuelta sería de utilidad. – configurator

+0

En cuyo caso, sería más sencillo utilizar una ArrayList para empezar. –

+0

ah, pero agregando el tipo incorrecto a la colección cuando se lanza como IList todavía a través de una excepción sobre si es del tipo incorrecto, ¿verdad? – Sekhat

1

Creo que lo mejor que vas a ser capaz de hacer es algo así como esto:

static void Main(string[] args) 
{ 
    int i = 1; 
    var thelist = CreateList(i); 
} 

public static List<T> CreateList<T>(T t) 
{ 
    return new List<T>(); 
} 
+1

que se basa en el compilador ser capaz de inferir el tipo - que significa que tiene que saber el tipo en tiempo de compilación. –

1

Si no conoce el tipo en tiempo de diseño, diría que usted tiene una lista de objetos (la clase base para todos los otros tipos).

List<object> list = new List<object>(); 
+1

No, aún puede crear una lista del tipo apropiado y pasarla a algo que pueda hacer un reparto del tipo correcto y trabajar con él de forma estática a partir de ese momento. El hecho de que una parte del código no sepa el tipo no significa que * nada * sepa el tipo. –

1

También puedes usar Activator.CreateInstance. código fragmento de ejemplo:

public class BaseRepository<T> where T : DataContext 
{ 
    protected T _dc; 

    public BaseRepository(string connectionString) 
    { 
     _dc = (T) Activator.CreateInstance(typeof(T), connectionString); 
    } 

    public void SubmitChanges() 
    { 
     _dc.SubmitChanges(); 
    } 
} 
0

ver la respuesta de la pregunta similar "Dynamically Create a Generic Type for Template". La única diferencia es que están generando el tipo desde la línea de comandos, el resto debería ser capaz de adaptarse a sus necesidades.

Dicho sea de paso, no se puede llamar typeof en una instancia - a obtener el tipo de una instancia (por ejemplo, "i" llamo GetType():

Type intType = i.GetType(); 
0

Si aún desea escribir .Add(), .Remove(), for foreach etc., puede tratar la Lista como un "viejo" System.Collections.IList regular, ya que esta interfaz se implementó por suerte por List < T>.

Y como todas las demás respuestas publicadas a esta pregunta muestran casi todas las otras formas posibles de crear una instancia de una lista < T> dinámicamente, mostraré una última forma de hacerlo. Personalmente uso este método al crear instancias genéricas, cuando realmente no sé nada sobre el tipo en tiempo de compilación, y el tipo debe pasar como una cadena, tal vez proveniente del archivo de configuración de la aplicación. En este ejemplo, T es System.string por simplicidad pero podría ser cualquier cosa:

Type T = typeof (string); // replace with actual T 
string typeName = string.Format (
    "System.Collections.Generic.List`1[[{0}]], mscorlib", T.AssemblyQualifiedName); 

IList list = Activator.CreateInstance (Type.GetType (typeName)) 
    as IList; 

System.Diagnostics.Debug.Assert (list != null); // 

list.Add ("string 1"); // new T 
list.Add ("string 2"); // new T 
foreach (object item in list) 
{ 
    Console.WriteLine ("item: {0}", item); 
} 
Cuestiones relacionadas