332 votes

Vérifiez si une classe est dérivée d'une classe générique

J'ai une classe générique dans mon projet avec des classes dérivées.

public class GenericClass : GenericInterface
{
}

public class Test : GenericClass
{
}

Existe-t-il un moyen de savoir si un objet de type Type est dérivé de GenericClass ?

t.IsSubclassOf(typeof(GenericClass<>))

ne fonctionne pas.

6voto

Menno Squared Points 140

S'appuyant sur l'excellente réponse ci-dessus de fir3rpho3nixx et David Schmitt, j'ai modifié leur code et ajouté le test ShouldInheritOrImplementTypedGenericInterface (dernier).

    /// 
    /// Découvrez si un type enfant implémente ou hérite du type parent.
    /// Le type parent peut être une interface ou une classe concrète, générique ou non générique.
    /// 
    /// 
    /// 
    /// 
    public static bool InheritsOrImplements(this Type child, Type parent)
    {
        var currentChild = parent.IsGenericTypeDefinition && child.IsGenericType ? child.GetGenericTypeDefinition() : child;

        while (currentChild != typeof(object))
        {
            if (parent == currentChild || HasAnyInterfaces(parent, currentChild))
                return true;

            currentChild = currentChild.BaseType != null && parent.IsGenericTypeDefinition && currentChild.BaseType.IsGenericType
                                ? currentChild.BaseType.GetGenericTypeDefinition()
                                : currentChild.BaseType;

            if (currentChild == null)
                return false;
        }
        return false;
    }

    private static bool HasAnyInterfaces(Type parent, Type child)
    {
        return child.GetInterfaces().Any(childInterface =>
            {
                var currentInterface = parent.IsGenericTypeDefinition && childInterface.IsGenericType
                    ? childInterface.GetGenericTypeDefinition()
                    : childInterface;

                return currentInterface == parent;
            });

    }

    [Test]
    public void ShouldInheritOrImplementNonGenericInterface()
    {
        Assert.That(typeof(FooImplementor)
            .InheritsOrImplements(typeof(IFooInterface)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementGenericInterface()
    {
        Assert.That(typeof(GenericFooBase)
            .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementGenericInterfaceByGenericSubclass()
    {
        Assert.That(typeof(GenericFooImplementor<>)
            .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter()
    {
        Assert.That(new GenericFooImplementor().GetType()
            .InheritsOrImplements(typeof(IGenericFooInterface<>)), Is.True);
    }

    [Test]
    public void ShouldNotInheritOrImplementGenericInterfaceByGenericSubclassNotCaringAboutGenericTypeParameter()
    {
        Assert.That(new GenericFooImplementor().GetType()
            .InheritsOrImplements(typeof(IGenericFooInterface)), Is.False);
    }

    [Test]
    public void ShouldInheritOrImplementNonGenericClass()
    {
        Assert.That(typeof(FooImplementor)
            .InheritsOrImplements(typeof(FooBase)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementAnyBaseType()
    {
        Assert.That(typeof(GenericFooImplementor<>)
            .InheritsOrImplements(typeof(FooBase)), Is.True);
    }

    [Test]
    public void ShouldInheritOrImplementTypedGenericInterface()
    {
        GenericFooImplementor obj = new GenericFooImplementor();
        Type t = obj.GetType();

        Assert.IsTrue(t.InheritsOrImplements(typeof(IGenericFooInterface)));
        Assert.IsFalse(t.InheritsOrImplements(typeof(IGenericFooInterface)));
    }

2voto

Cirem Points 67

JaredPar,

Cela n'a pas fonctionné pour moi si je passe typeof (type <>) comme toCheck. Voici ce que j'ai changé.

static bool IsSubclassOfRawGeneric(Type generic, Type toCheck) {
    while (toCheck != typeof(object)) {
        var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
          if (cur.IsGenericType && generic.GetGenericTypeDefinition() == cur.GetGenericTypeDefinition()) {
            return true;
        }
        toCheck = toCheck.BaseType;
    }
    return false;
}

2voto

Ken Kin Points 1604

@EnocNRoll - La réponse d'Ananda Gopal est intéressante, mais en cas d'instance non instanciée au préalable ou si vous souhaitez vérifier avec une définition de type générique, je suggérerais cette méthode:

public static bool TypeIs(this Type x, Type d) {
    if(null==d) {
        return false;
    }

    for(var c = x; null!=c; c=c.BaseType) {
        var a = c.GetInterfaces();

        for(var i = a.Length; i-->=0;) {
            var t = i<0 ? c : a[i];

            if(t==d||t.IsGenericType&&t.GetGenericTypeDefinition()==d) {
                return true;
            }
        }
    }

    return false;
}

et l'utiliser comme suit:

var b = typeof(char[]).TypeIs(typeof(IList<>)); // true

Il y a quatre cas conditionnels où à la fois t(à tester) et d sont des types génériques et deux cas sont couverts par t==d qui sont (1)ni t ni d n'est une définition générique ou (2) les deux sont des définitions génériques. Les autres cas sont l'un d'entre eux est une définition générique, seulement lorsque d est déjà une définition générique nous avons la possibilité de dire un t est un d mais pas l'inverse.

Cela devrait fonctionner avec des classes ou interfaces arbitraires que vous souhaitez tester, et renvoie comme si vous testiez une instance de ce type avec l'opérateur is.

0voto

Type _type = myclass.GetType();
PropertyInfo[] _propertyInfos = _type.GetProperties();
Boolean _test = _propertyInfos[0].PropertyType.GetGenericTypeDefinition() == typeof(List<>);

0voto

Yaseen Points 11

Vous pouvez essayer cette extension

    public static bool IsSubClassOfGenericClass(this Type type, Type genericClass,Type t)
    {
        return type.IsSubclassOf(genericClass.MakeGenericType(new[] { t }));
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X