Comment puis-je vérifier si un type est un sous-type OU le type d'un objet?

Pour vérifier si un type est une sous-classe d'un autre type en C#, c'est facile:

typeof (SubClass).IsSubclassOf(typeof (BaseClass)); // returns true

Cependant, cela échouera:

typeof (BaseClass).IsSubclassOf(typeof (BaseClass)); // returns false

Existe-t-il un moyen de vérifier si un type est une sous-classe ou de la classe de base elle-même, sans utiliser un opérateur OR ou utiliser une méthode d'extension?

281
demandé sur abatishchev 2010-04-30 08:23:33

5 réponses

Apparemment, non.

Voici les options:

Type.IsSubclassOf

Comme vous l'avez déjà découvert, cela ne fonctionnera pas si les deux types sont les mêmes, voici un exemple de programme LINQPad qui démontre:

void Main()
{
    typeof(Derived).IsSubclassOf(typeof(Base)).Dump();
    typeof(Base).IsSubclassOf(typeof(Base)).Dump();
}

public class Base { }
public class Derived : Base { }

Sortie:

True
False

Qui indique que Derived est une sous-classe de Base, mais que Base n'est (évidemment) pas une sous-classe en soi.

Type.IsAssignableFrom

Maintenant, cela répondra à votre question particulière, mais cela vous donnera aussi des faux positifs. Comme Eric Lippert l'a souligné dans les commentaires, alors que la méthode retournera en effet True pour les deux questions ci-dessus, elle retournera également True pour celles-ci, ce que vous ne voulez probablement pas:

void Main()
{
    typeof(Base).IsAssignableFrom(typeof(Derived)).Dump();
    typeof(Base).IsAssignableFrom(typeof(Base)).Dump();
    typeof(int[]).IsAssignableFrom(typeof(uint[])).Dump();
}

public class Base { }
public class Derived : Base { }

Ici vous obtenez la sortie suivante:

True
True
True

Le Dernier True indique, si le méthode seulement répondu à la question posée, que uint[] hérite de int[], ou qu'ils sont du même type, ce qui n'est clairement pas le cas.

, Donc IsAssignableFrom n'est pas tout à fait exact non plus.

is et as

Le" problème " avec is et as dans le contexte de votre question Est qu'ils vous obligeront à opérer sur les objets et à écrire l'un des types directement dans le code, et à ne pas travailler avec les objets Type.

En d'autres termes, ce ne sera pas compilez:

SubClass is BaseClass
^--+---^
   |
   +-- need object reference here

Ce ne sera pas non plus:

typeof(SubClass) is typeof(BaseClass)
                    ^-------+-------^
                            |
                            +-- need type name here, not Type object

Ce ne sera pas non plus:

typeof(SubClass) is BaseClass
^------+-------^
       |
       +-- this returns a Type object, And "System.Type" does not
           inherit from BaseClass

Conclusion

Bien que les méthodes ci-dessus puissent répondre à vos besoins, la seule réponse correcte à votre question (telle que je la vois) est que vous aurez besoin d'un chèque supplémentaire:

typeof(Derived).IsSubclassOf(typeof(Base)) || typeof(Derived) == typeof(Base);

Ce qui bien sûr a plus de sens dans une méthode:

public bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant)
{
    return potentialDescendant.IsSubclassOf(potentialBase)
           || potentialDescendant == potentialBase;
}
409
répondu Lasse Vågsæther Karlsen 2014-07-04 13:42:16
typeof(BaseClass).IsAssignableFrom(unknownType);
26
répondu Marc Gravell 2010-04-30 04:26:29

Vous devriez essayer d'utiliser Type.IsAssignableFrom à la place.

7
répondu Thomas 2010-04-30 04:26:50

Si vous essayez de le faire dans un projet Xamarin Forms PCL, les solutions ci-dessus utilisant IsAssignableFrom donnent une erreur:

Erreur: 'Type' ne contient pas de définition pour 'IsAssignableFrom' et aucune méthode d'extension 'IsAssignableFrom' n'accepte un premier argument de type 'Type' pourrait être trouvé (il vous manque une directive using ou un référence d'assemblage?)

Parce que IsAssignableFrom demande un objet TypeInfo. Vous pouvez utiliser la méthode GetTypeInfo() de System.Reflection:

typeof(BaseClass).GetTypeInfo().IsAssignableFrom(typeof(unknownType).GetTypeInfo())

1
répondu BrunoSerrano 2018-03-21 13:34:10

Je poste cette réponse avec l'espoir de quelqu'un partage avec moi si et pourquoi ce serait une mauvaise idée. Dans mon application, j'ai une propriété de Type que je veux vérifier pour être sûr qu'il est typeof(A) ou typeof(B), où B est toute classe dérivée de A. Donc mon code:

public class A
{
}

public class B : A
{
}

public class MyClass
{
    private Type _helperType;
    public Type HelperType
    {
        get { return _helperType; }
        set 
        {
            var testInstance = (A)Activator.CreateInstance(value);
            if (testInstance==null)
                throw new InvalidCastException("HelperType must be derived from A");
            _helperType = value;
        }
    }
}

J'ai l'impression d'être un peu naïf ici, donc tout commentaire serait le bienvenu.

0
répondu baskren 2016-09-12 10:58:42