type multiple method generic c# generics reflection types

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 si c y el Type actual representan el mismo tipo, o si el Type actual está en la jerarquía de herencia de c , o si el Type actual es una interfaz que c implementa, o si c es un parámetro de tipo genérico y el Type actual representa una de las restricciones de c . false si ninguna de estas condiciones es verdadera, o si c es null .

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 tipo MyGenericList<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{} }