2010-01-19 8 views
5

¿Hay alguna manera de decir, mediante reflexión, que una lista genérica de tipo A está relacionada con una lista genérica de tipo B? Por ejemplo, tengo un List<string> y un List<int>. ¿Cómo puedo saber a través de la reflexión que ambos tipos son 'instancias' de List<T>. Creo que tengo un problema porque List<T> no es un tipo real. No puede hacer typeof(List<T>) por ejemplo. List<T> es un truco de compilación, supongo. Entonces, ¿hay alguna forma de determinar si dos tipos diferentes provienen del List<T>?Relación entre instancias de la lista <T>

+0

Usted debe leer acerca de los genéricos antes de escribir código como eso. – alga

+1

@alga ¿Qué hay de malo con el código? Están intentando aprender más sobre los genéricos y han formulado una pregunta fantástica de la que dudo mucho. Los programadores de .NET conocen la respuesta. – Eilon

+1

Estoy de acuerdo con Eilon. – Josh

Respuesta

8

Claro que puedes ... List<> es en realidad lo que se llama una "tipo genérico no vinculado", lo que significa que no se ha parametrizado con un tipo. Cuando se especifica el argumento tipo, se denomina "tipo genérico enlazado". Un tipo que involucra parámetros de tipo "en bruto", como List<T> es un "tipo genérico abierto" y uno que solo involucra tipos reales, como List<int> es un "tipo genérico cerrado". La única situación en la que se puede usar un tipo genérico no vinculado en C# está en el operador typeof. Para acceder al tipo sin consolidar o un tipo cerrado que haría: GetGenericTypeDefinition

Type listOfT = typeof(List<>); // unbound type 
Type listOfString = typeof(List<string>); // closed bound type 
Type listOfInt32 = typeof(List<int>); // closed bound type 

Assert.IsTrue(listOfString.IsGenericType); 

Assert.AreEqual(typeof(string), listOfString.GetGenericTypeParameters()[0]); 
Assert.AreEqual(typeof(List<>), listOfString.GetGenericTypeDefinition()); 

Type setOfString = typeof(HashSet<string>); 

Assert.AreNotEqual(typeof(List<>), setOfString.GetGenericTypeDefinition()); 
+0

Ah Ok. Ya veo. Eso parece estar funcionando. Sin embargo, un problema que tengo es que el nombre del objeto Type que vuelve de List <> es 'System.RuntimeType'. Si hago lo mismo para HashSet , también obtengo un tipo llamado 'System.RuntimeType'. Son dos objetos Tipo diferentes con el mismo nombre. Entonces, ¿cómo puedo distinguirlos? Necesito persistir esta información en alguna parte y no tengo nada que persistir ya que no obtengo un nombre como 'System.List <>' que pueda entender. – BowserKingKoopa

+0

Sí, ambos son RuntimeType de la misma forma que "hello" .GetType() y 123.GetType() son ambos System.Type, pero representan dos tipos diferentes. Puede examinar la propiedad FullName si lo desea, pero si está tratando de probar si un tipo particular es listOfT, entonces debe comparar la igualdad como se muestra arriba. – Josh

+0

FullName también devuelve simplemente 'System.RuntimeType'. Como no puedo obtener ningún nombre único de los tipos que vuelven de System.GetGenericTypeDefinition(), no puedo insistir en el hecho de que el tipo procede de una lista . Intento persistir estos tipos usando sus Nombres. Así que dos tipos diferentes con el mismo nombre me están aturdiendo. – BowserKingKoopa

5

En realidad List<T> es un tipo real en muchos aspectos (se puede utilizar typeof(List<>), por ejemplo), y List<T> es no simplemente un truco compilador, pero un truco tiempo de ejecución. Pero se puede de hecho comprobar el tipo genérico abierto, a través de algo como:

static Type GetRawType(Type type) 
    { 
     return type.IsGenericType ? type.GetGenericTypeDefinition() : type; 
    } 
    static void Main() 
    { 
     List<int> list1 = new List<int>(); 
     List<string> list2 = new List<string>(); 
     Type type1 = GetRawType(list1.GetType()), 
      type2 = GetRawType(list2.GetType()); 
     Console.WriteLine(type1 == type2); // true 
    } 
+0

GetGenericTypeDefinition() siempre devuelve un tipo de System.RuntimeType. Eso no es exactamente lo que estoy buscando. Esperaba recuperar 'System.List ' o algo así. Estoy seguro de que muchas cosas son System.RuntimeType que no tienen nada que ver con la lista . ¿Estoy haciendo algo mal? – BowserKingKoopa

+0

Tal vez debería volver a formular la pregunta. ¿Cómo puedo saber si un tipo determinado proviene de la lista '? – BowserKingKoopa

+1

@Bowser, GetGenericTypeDefinition() es lo que desea. bool isListOfT = type.IsGenericType && (type.GetGenericTypeDefinition() == typeof (List <>)); – Josh

1

Llamar:

List<string> l1 = new List<string>(); 
    List<int> l2 = new List<int>(); 
    Type t1 = l1.GetType().GetGenericTypeDefinition(); 
    Type t2 = l2.GetType().GetGenericTypeDefinition(); 
    Console.Write(t1 == t2);//output: true; 
Cuestiones relacionadas