Tengo una clase genérica en mi proyecto con clases derivadas.
public class GenericClass<T> : GenericInterface<T>
{
}
public class Test : GenericClass<SomeType>
{
}
¿Hay alguna forma de averiguar si un Type
objeto se deriva GenericClass
?
t.IsSubclassOf(typeof(GenericClass<>))
No funciona.
c#
generics
reflection
bernhardrusch
fuente
fuente
(Publicado nuevamente debido a una reescritura masiva)
La respuesta del código de JaredPar es fantástica, pero tengo un consejo que lo haría innecesario si sus tipos genéricos no se basan en parámetros de tipo de valor. Estaba convencido de por qué el operador "es" no funcionaría, por lo que también he documentado los resultados de mi experimentación para referencia futura. Mejore esta respuesta para mejorar aún más su claridad.
PROPINA:
Si se asegura de que su implementación de GenericClass hereda de una clase base abstracta no genérica como GenericClassBase, puede hacer la misma pregunta sin ningún problema:
IsSubclassOf ()
Mi prueba indica que IsSubclassOf () no funciona en tipos genéricos sin parámetros como
mientras que funcionará con
Por lo tanto, el siguiente código funcionará para cualquier derivación de GenericClass <>, suponiendo que esté dispuesto a realizar pruebas basadas en SomeType:
La única vez que puedo imaginar que querrías probar GenericClass <> es en un escenario de marco de plug-in.
Reflexiones sobre el operador "es"
En tiempo de diseño, C # no permite el uso de genéricos sin parámetros porque en ese momento no son esencialmente un tipo CLR completo. Por lo tanto, debe declarar variables genéricas con parámetros, y es por eso que el operador "es" es tan poderoso para trabajar con objetos. Por cierto, el operador "es" tampoco puede evaluar tipos genéricos sin parámetros.
El operador "es" probará toda la cadena de herencia, incluidas las interfaces.
Entonces, dada una instancia de cualquier objeto, el siguiente método hará el truco:
Esto es algo redundante, pero pensé que seguiría adelante y lo visualizaría para todos.
Dado
Las siguientes líneas de código devolverían verdadero:
Por otro lado, si desea algo específico para GenericClass, podría hacerlo más específico, supongo, así:
Entonces probarías así:
fuente
Type
objeto.typeof
operador. Según los documentos: "El operador typeof se utiliza para obtener el objeto System.Type para un tipo".Trabajé con algunas de estas muestras y descubrí que en algunos casos faltaban. Esta versión funciona con todo tipo de genéricos: tipos, interfaces y definiciones de tipos de los mismos.
Aquí están las pruebas unitarias también:
fuente
!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent;
así que reemplaza esa variable con la expansión de la instrucción if:if (parent.IsGenericType && shouldUseGenericType)
y obtiene loif (parent.IsGenericType && (!parent.IsGenericType || parent.GetGenericTypeDefinition() == parent))
que luego se reduce aif (parent.IsGenericType && parent.GetGenericTypeDefinition() == parent)) parent = parent.GetGenericTypeDefinition();
int j = 0;
if (j is an int && j == 0)
{ j=0; }
¿Estoy confundiendo mis iguales de referencia y mis iguales de valor? Pensé que solo había una instancia de cada Tipo en la memoria, por lo que dos variables que apuntan al mismo tipo apuntan de hecho a la misma ubicación en la memoria.Me parece que esta implementación funciona en más casos (clase genérica e interfaz con o sin parámetros iniciados, independientemente de la cantidad de elementos secundarios y parámetros):
Aquí están mis
7076 casos de prueba:Clases e interfaces para pruebas:
fuente
El código de JaredPar funciona pero solo para un nivel de herencia. Para niveles ilimitados de herencia, use el siguiente código
fuente
while
código en JaredPar cubre niveles ilimitados.Aquí hay un pequeño método que creé para verificar que un objeto se deriva de un tipo específico. ¡Funciona muy bien para mí!
fuente
Puede ser excesivo, pero uso métodos de extensión como los siguientes. Comprueban las interfaces y las subclases. También puede devolver el tipo que tiene la definición genérica especificada.
Por ejemplo, para el ejemplo en la pregunta, puede probar contra la interfaz genérica y la clase genérica. El tipo devuelto se puede usar
GetGenericArguments
para determinar que el tipo de argumento genérico es "SomeType".fuente
Sobre la base de la excelente respuesta anterior de fir3rpho3nixx y David Schmitt, modifiqué su código y agregué la prueba ShouldInheritOrImplementTypedGenericInterface (última).
fuente
Todo esto se puede hacer fácilmente con linq. Esto encontrará cualquier tipo que sea una subclase de la clase base genérica GenericBaseType.
fuente
Solución simple: simplemente cree y agregue una segunda interfaz no genérica a la clase genérica:
A continuación, sólo para comprobar que, en cualquier forma que desee utilizar
is
,as
,IsAssignableFrom
, etc.Obviamente solo es posible si tiene la capacidad de editar la clase genérica (que parece tener el OP), pero es un poco más elegante y legible que usar un método de extensión críptico.
fuente
IGenericClass
no le garantizará esoGenericClass
o siGenericInterface
realmente se extiende o implementa. Esto significa que su compilador tampoco le permitirá acceder a ningún miembro de la clase genérica.Agregado a la respuesta de @ jaredpar, esto es lo que uso para verificar las interfaces:
Ex:
fuente
JaredPar,
Esto no funcionó para mí si paso typeof (type <>) como toCheck. Esto es lo que cambié.
fuente
typeof(type<>)
comotoCheck
. También realmente necesita la verificación nula como en la solución de JaredPar. Además, no sé qué más está logrando al reemplazarcur == generic
su solución porcur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()
otra que no sea restringir su método para que funcione solo para tipos genéricos. En otras palabras, algo como esto falla con una excepción:IsSubclassOfRawGeneric(typeof(MyClass), typeof(MyClass<>))
@EnocNRoll: la respuesta de Ananda Gopal es interesante, pero en caso de que una instancia no se instancia de antemano o si desea verificar con una definición de tipo genérico, sugeriría este método:
y úsalo como:
Hay cuatro casos condicionales cuando ambos
t
(para ser probados) yd
son tipos genéricos y dos casos están cubiertos por lost==d
cuales (1) nit
tampocod
es una definición genérica o (2) ambos son definiciones genéricas . Los casos de descanso son una de ellas es una definición genérica, sólo cuandod
ya existe una definición genérica que tenemos la oportunidad de decir unat
es unad
, pero no viceversa.Debería funcionar con clases o interfaces arbitrarias que desea probar, y devuelve lo que sucede si prueba una instancia de ese tipo con el
is
operador.fuente
fuente
Puedes probar esta extensión
fuente
tarde al juego en esto ... yo también tengo otra permutación de la respuesta de JarodPar.
aquí está Type.IsSubClassOf (Type) cortesía del reflector:
a partir de eso, vemos que no está haciendo nada demasiado y es similar al enfoque iterativo de JaredPar. Hasta aquí todo bien. aquí está mi versión (descargo de responsabilidad: no se ha probado exhaustivamente, así que déjame saber si encuentras problemas)
Básicamente, este es solo un método de extensión para System.Type: hice esto para limitar intencionalmente el Tipo "thisType" a Tipos concretos, ya que mi uso inmediato es la consulta LINQ "donde" predica con los objetos Type. Estoy seguro de que todos ustedes, amigos inteligentes, podrían atribuirlo a un método estático eficiente y multipropósito si lo necesitan :) el código hace algunas cosas que el código de la respuesta no
el resto es básicamente el mismo que el código de JaredPar
fuente