对'open'泛型类型使用IsAssignableFrom

使用反射,我试图找到从给定的基类继承的类型集。 找出简单的类型并不需要很长时间,但是当涉及到泛型时,我却难以理解。

对于这段代码,第一个IsAssignableFrom返回true,但第二个返回false。 然而,最终的任务编译得很好。

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>();
    }
}

那么如何在运行时确定一个泛型类型定义是否是从另一个泛型定义派生的呢?


从答案到另一个问题:

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);
}

(如果你喜欢这个答案,请上传链接的答案,因为代码不是我的。)


您发布的确切代码不会返回令人意外的结果。

这说“错误”:

Type g1 = typeof(generic1<>);
Type g2 = typeof(generic2<>);
Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));

这说“真”:

Type g1 = typeof(generic1<class1>);
Type g2 = typeof(generic2<class1>);
Console.WriteLine("g1.IsAssignableFrom(g2): {0}", g1.IsAssignableFrom(g2));

不同之处在于,开放的泛型类型不能有实例,所以一个对另一个不是“可分配的”。

从文档:

返回true如果c和当前Type表示相同的类型,或者如果当前Type是在继承层次结构c ,或者如果当前Type是一个接口, c器具,或者如果c是一个通用的类型参数和当前Type代表c的约束之一。 false如果这些条件都为真,或者如果cnull

在这种情况下,显然这些条件都不是真的。 还有一个额外的说明:

通用类型定义不能从封闭构造类型分配。 也就是说,您不能将封闭的构造类型MyGenericList<int> (Visual Basic中的MyGenericList(Of Integer) )分配给MyGenericList<T>类型的变量。


在以下情况下,使用Konrad Rudolph提供的方法可能是错误的,如:IsAssignableToGenericType(typeof(A),typeof(A <>)); //返回false

我认为这是一个更好的答案

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;
}

测试用例,请参阅在C#泛型中使用IsAssignableFrom获取详细信息

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 stackoverflow - 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 stackoverflow - 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{}
}
链接地址: http://www.djcxy.com/p/57401.html

上一篇: Using IsAssignableFrom with 'open' generic types

下一篇: How do I tell whether a Type implements IList<>?