c# - multiple - Usar IsAssignableFrom con tipos genéricos ''abiertos''
gettype of generic c# (4)
Usando la reflexión, intento encontrar el conjunto de tipos que heredan de una clase base determinada. No pasó mucho tiempo para descubrir tipos simples, pero estoy perplejo cuando se trata de genéricos.
Para este fragmento de código, el primer IsAssignableFrom devuelve verdadero, pero el segundo devuelve falso. Y, sin embargo, la tarea final compila muy bien.
class class1 { }
class class2 : class1 { }
class generic1<T> { }
class generic2<T> : generic1<T> { }
class Program
{
static void Main(string[] args)
{
Type c1 = typeof(class1);
Type c2 = typeof(class2);
Console.WriteLine("c1.IsAssignableFrom(c2): {0}", c1.IsAssignableFrom(c2));
Type g1 = typeof(generic1<>);
Type g2 = typeof(generic2<>);
Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));
generic1<class1> cc = new generic2<class1>();
}
}
Entonces, ¿cómo determino en tiempo de ejecución si una definición de tipo genérico se deriva de otra?
De la respuesta a otra pregunta :
public static bool IsAssignableToGenericType(Type givenType, Type genericType)
{
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
{
if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
return true;
}
if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return IsAssignableToGenericType(baseType, genericType);
}
(Si te gusta la respuesta, vota la respuesta vinculada porque el código no es mío).
El código exacto que publicaste no arroja resultados sorprendentes.
Esto dice "falso":
Type g1 = typeof(generic1<>);
Type g2 = typeof(generic2<>);
Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));
Esto dice "verdadero":
Type g1 = typeof(generic1<class1>);
Type g2 = typeof(generic2<class1>);
Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));
La diferencia es que los tipos genéricos abiertos no pueden tener instancias, por lo que uno no es "asignable" para el otro.
De los docs :
Devuelve
true
sic
y elType
actual representan el mismo tipo, o si elType
actual está en la jerarquía de herencia dec
, o si elType
actual es una interfaz quec
implementa, o sic
es un parámetro de tipo genérico y elType
actual representa una de las restricciones dec
.false
si ninguna de estas condiciones es verdadera, o sic
esnull
.
En este caso, claramente ninguna de estas condiciones es verdadera. Y hay una nota extra:
Una definición de tipo genérico no se puede asignar desde un tipo construido cerrado. Es decir, no puede asignar el tipo construido cerrado
MyGenericList<int>
(MyGenericList(Of Integer)
en Visual Basic) a una variable de tipoMyGenericList<T>
.
En el siguiente caso, utilice el método proporcionado por Konrad Rudolph que podría ser incorrecto, como: IsAssignableToGenericType (typeof (A), typeof (A <>); // return false
Creo que esta es una respuesta mejor
public static bool IsAssignableFrom(Type extendType, Type baseType)
{
while (!baseType.IsAssignableFrom(extendType))
{
if (extendType.Equals(typeof(object)))
{
return false;
}
if (extendType.IsGenericType && !extendType.IsGenericTypeDefinition)
{
extendType = extendType.GetGenericTypeDefinition();
}
else
{
extendType = extendType.BaseType;
}
}
return true;
}
el caso de prueba, consulte Uso de IsAssignableFrom con genéricos de C # para obtener más información
using System;
/**
* Sam Sha - yCoder.com
*
* */
namespace Test2
{
class MainClass
{
public static void Main (string[] args)
{
string a = "ycoder";
Console.WriteLine(a is object);
A aa = new A();
//Console.WriteLine(aa is A<>);//con''t write code like this
typeof(A<>).IsAssignableFrom(aa.GetType());//return false
Trace(typeof(object).IsAssignableFrom(typeof(string)));//true
Trace(typeof(A<>).IsAssignableFrom(typeof(A)));//false
AAA aaa = new AAA();
Trace("Use IsTypeOf:");
Trace(IsTypeOf(aaa, typeof(A<>)));
Trace(IsTypeOf(aaa, typeof(AA)));
Trace(IsTypeOf(aaa, typeof(AAA<>)));
Trace("Use IsAssignableFrom from - not right:");
Trace(IsAssignableFrom(typeof(A), typeof(A<>))); // error
Trace(IsAssignableFrom(typeof(AA), typeof(A<>)));
Trace(IsAssignableFrom(typeof(AAA), typeof(A<>)));
Trace("Use IsAssignableToGenericType:");
Trace(IsAssignableToGenericType(typeof(A), typeof(A<>)));
Trace(IsAssignableToGenericType(typeof(AA), typeof(A<>)));
Trace(IsAssignableToGenericType(typeof(AAA), typeof(A<>)));
}
static void Trace(object log){
Console.WriteLine(log);
}
public static bool IsTypeOf(Object o, Type baseType)
{
if (o == null || baseType == null)
{
return false;
}
bool result = baseType.IsInstanceOfType(o);
if (result)
{
return result;
}
return IsAssignableFrom(o.GetType(), baseType);
}
public static bool IsAssignableFrom(Type extendType, Type baseType)
{
while (!baseType.IsAssignableFrom(extendType))
{
if (extendType.Equals(typeof(object)))
{
return false;
}
if (extendType.IsGenericType && !extendType.IsGenericTypeDefinition)
{
extendType = extendType.GetGenericTypeDefinition();
}
else
{
extendType = extendType.BaseType;
}
}
return true;
}
//from - not good enough
public static bool IsAssignableToGenericType(Type givenType, Type genericType) {
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
if (it.IsGenericType)
if (it.GetGenericTypeDefinition() == genericType) return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return baseType.IsGenericType &&
baseType.GetGenericTypeDefinition() == genericType ||
IsAssignableToGenericType(baseType, genericType);
}
}
class A{}
class AA : A{}
class AAA : AA{}
}
Necesitas comparar el tipo contenido. Ver: ¿Cómo obtener el tipo de T de un miembro de una clase o método genérico?
En otras palabras, creo que debe verificar si el tipo que contiene la clase genérica es asignable en lugar de la clase genérica en sí misma.