2011-04-08 9 views
5

que tienen las siguientes clases genéricas:¿Cómo probar si dos genéricos tienen una relación base-subclase sin instanciarlos?

class Base<T> where T : ... { ... } 
class Derived<T> : Base<T> where T : ... { ... } 
class Another<T> where T : ... { ... } 
class DerivedFromDerived<T> : Derived<T> where T : ... { ... } 

En algún lugar de mi código, me gustaría probar si una hereda genérico que se da a partir Base<T>, sin crear una instancia particular de los genéricos. ¿Cómo puedo hacer eso?

static bool DerivedFromBase(Type type) { /* ??? */ } 

static void Main(string[] args) 
{ 
    Console.WriteLine(DerivedFromBase(typeof(Derived<>)));   // true 
    Console.WriteLine(DerivedFromBase(typeof(Another<>)));   // false 
    Console.WriteLine(DerivedFromBase(typeof(DerivedFromDerived<>))); // true 
    Console.ReadKey(true); 
} 

EDIT: Gracias Marcos. Ahora veo la luz. Intenté originalmente lo siguiente:

typeof(Derived<>).BaseType == typeof(Base<>) 

Aparentemente, esto es correcto. Pero no lo es. El problema es que Base 's T no es lo mismo que Derived' s T. Por lo tanto, en

typeof(Base<>) 

Base 's T es un tipo libre. Pero, en

typeof(Derived<>).BaseType 

Base 's T está obligado a Derived' s T, que es a su vez un tipo libre. (Esto es tan impresionante Me AMOR para ver la System.Reflection 'código fuente s!) Ahora,

typeof(Derived<>).BaseType.GetGenericTypeDefinition() 

unbounds Base' s T. Conclusión:

typeof(Derived<>).BaseType.GetGenericTypeDefinition() == typeof(Base<>) 

Y ahora, si todos discúlpenme, mi cabeza está ardiendo.

+0

Estoy interesado en recibir respuestas aquí, porque yo creo * * '' Derivado no es una subclase de '' Base

+0

@ Matt Greer: De hecho, '' Derivado no es una subclase de '' Base . – pyon

+0

Creo que Mark ha respondido correctamente a su pregunta, pero creo que podría querer decir algo más como Matt mencionó anteriormente. ¿Podrías aclarar? – briantyler

Respuesta

6

No estoy seguro si esto es lo que está buscando, pero creo que "IsAssignableFrom" hará el truco.

class Program 
{ 
    class Base<T> { } 
    class Derived<T> : Base<T> { } 
    class Another<T> { } 
    class DerivedFromDerived<T> : Derived<T> { } 

    static bool DerivedFromBase<T>(Type type) 
    { 
     return typeof(Base<T>).IsAssignableFrom(type); 
    } 

    static void Main(string[] args) 
    { 
     Console.WriteLine(DerivedFromBase<int>(typeof(Derived<int>)));   // true  
     Console.WriteLine(DerivedFromBase<int>(typeof(Another<int>)));   // false  
     Console.WriteLine(DerivedFromBase<int>(typeof(DerivedFromDerived<int>))); // true 
     Console.ReadKey(true); 
    } 
} 

para manejar el tipo base abierta:

static bool DerivedFromBase(Type type) 
    { 
     Type openBase = typeof(Base<>); 

     var baseType = type; 

     while (baseType != typeof(Object) && baseType != null) 
     { 
      if (baseType.GetGenericTypeDefinition() == openBase) return true; 

      baseType = baseType.BaseType; 
     } 
     return false; 
    } 
+0

Aunque esto podría no ser lo que está buscando porque maneja tipos genéricos abiertos en su código original typeof (Derived <>) en lugar de proporcionar un tipo concreto para T. – MarkPflug

+0

Necesito que la función funcione en genéricos abiertos. De lo contrario ... tendré que volver a pensar (y, lo más importante, ¡rehacer!) Mi trabajo de aproximadamente una semana. – pyon

+0

Sí, pensé que podría ser el caso. Se agregó una muestra para las pruebas de tipo abierto. Espero que funcione para usted. – MarkPflug

0

se me ha ocurrido con esta versión, aunque parece un poco hacky.

private static bool IsDerivedFrom(Type derivedType, Type baseType) 
{ 
    if (derivedType.BaseType == null) 
     return false; 

    if (derivedType.BaseType.GUID == baseType.GUID) 
     return true; 

    return IsDerivedFrom(derivedType.BaseType, baseType); 
} 

se basa en todos los tipos que tienen diferentes GUID, que debe ser cierto, pero, obviamente, una colisión ocurrirá el próximo jueves.

+0

¿Por qué guid? ¿Por qué no una comparación directa? – nawfal

Cuestiones relacionadas