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?
5 réponses
Apparemment, non.
Voici les options:
- Utiliser Type.IsSubclassOf
- Utiliser Type.IsAssignableFrom
-
is
etas
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;
}
Vous devriez essayer d'utiliser Type.IsAssignableFrom à la place.
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())
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.