réflexion dans C#
offre-t-il un moyen de déterminer si un type donné System.Type
modélise une interface?
public interface IMyInterface {}
public class MyType : IMyInterface {}
// should yield 'true'
typeof(MyType)./* ????? */MODELS_INTERFACE(IMyInterface);
Tu as quelques choix à choisir
typeof(IMyInterface).IsAssignableFrom(typeof(MyType))
typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface))
Pour une interface générique, c'est un peu différent.
typeof(MyType).GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMyInterface<>))
Utilisez Type.IsAssignableFrom
:
_typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
_
typeof(IMyInterface).IsAssignableFrom(someclass.GetType());
ou
typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
public static bool ImplementsInterface( this Type type, Type ifaceType ) {
Type[] intf = type.GetInterfaces();
for ( int i = 0; i < intf.Length; i++ ) {
if ( intf[ i ] == ifaceType ) {
return true;
}
}
return false;
}
Je pense que ceci est la version correcte, pour trois raisons:
1) Il utilise GetInterfaces et non IsAssignableFrom, il est plus rapide car IsAssignableFrom appelle finalement GetInterfaces après plusieurs vérifications.
2) Il effectue une itération sur le tableau local, il n'y aura donc pas de vérification des limites.
3) Il utilise l'opérateur == qui est défini pour Type. Il est donc probablement plus sûr que la méthode Equals (que l'appel Contains utilisera éventuellement).
Je viens de faire:
public static bool Implements<I>(this Type source) where I : class
{
return typeof(I).IsAssignableFrom(source);
}
J'aurais aimé pouvoir dire where I : interface
, mais interface
n'est pas une option de contrainte de paramètre générique. class
est aussi proche que possible.
Usage:
if(MyType.Implements<IInitializable>())
MyCollection.Initialize();
Je viens de dire Implements
parce que c'est plus intuitif. J'ai toujours IsAssignableFrom
en bascule.
Comme quelqu'un d'autre l'a déjà mentionné: Benjamin, le 10 avr. 13 à 22:21 "
Il était facile de ne pas y prêter attention et d’avoir les arguments pour IsAssignableFrom à rebours. Je vais maintenant avec GetInterfaces: p -
Bien, une autre solution consiste simplement à créer une méthode d’extension courte qui respecte, dans une certaine mesure, la façon de penser "la plus habituelle" (et convient que c’est un choix personnel très limité pour la rendre légèrement "plus naturelle" en fonction de ses préférences. ):
public static class TypeExtensions
{
public static bool IsAssignableTo(this Type type, Type assignableType)
{
return assignableType.IsAssignableFrom(type);
}
}
Et pourquoi ne pas aller un peu plus générique (enfin, je ne sais pas si c'est vraiment intéressant, eh bien, je suppose que je ne fais que passer à une autre pincée de sucre 'syntaxant'):
public static class TypeExtensions
{
public static bool IsAssignableTo(this Type type, Type assignableType)
{
return assignableType.IsAssignableFrom(type);
}
public static bool IsAssignableTo<TAssignable>(this Type type)
{
return IsAssignableTo(type, typeof(TAssignable));
}
}
Je pense que cela pourrait être beaucoup plus naturel, mais encore une fois, c'est une question d'opinions très personnelles:
var isTrue = michelleType.IsAssignableTo<IMaBelle>();
Modifier la réponse de Jeff pour une performance optimale (grâce au test de performance de Pierre Arnaud):
var type = typeof(MyType);
var implementsInterface = typeof(IMyInterface).IsAssignableFrom(type) && type.IsClass;
Pour trouver tous les types qui implémentent une interface dans un Assembly
donné:
var implementations = typeof(TypeInTargetAssembly).Assembly.GetTypes()
.Where(t => typeof(IMyInterface).IsAssignableFrom(t) && t.IsClass);
IsAssignableFrom
est maintenant déplacé vers TypeInfo
:
typeof(ISMSRequest).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo());
Une réponse correcte est
typeof(MyType).GetInterface(nameof(IMyInterface)) != null;
Cependant,
typeof(MyType).IsAssignableFrom(typeof(IMyInterface));
peut renvoyer un résultat incorrect, comme le code suivant le montre avec string et IConvertible:
static void TestIConvertible()
{
string test = "test";
Type stringType = typeof(string); // or test.GetType();
bool isConvertibleDirect = test is IConvertible;
bool isConvertibleTypeAssignable = stringType.IsAssignableFrom(typeof(IConvertible));
bool isConvertibleHasInterface = stringType.GetInterface(nameof(IConvertible)) != null;
Console.WriteLine($"isConvertibleDirect: {isConvertibleDirect}");
Console.WriteLine($"isConvertibleTypeAssignable: {isConvertibleTypeAssignable}");
Console.WriteLine($"isConvertibleHasInterface: {isConvertibleHasInterface}");
}
Résultats:
isConvertibleDirect: True
isConvertibleTypeAssignable: False
isConvertibleHasInterface: True
Qu'en est-il de
typeof(IWhatever).GetTypeInfo().IsInterface
Notez que si vous avez une interface générique IMyInterface<T>
, elle retournera toujours false
:
typeof(IMyInterface<>).IsAssignableFrom(typeof(MyType)) /* ALWAYS FALSE */
Cela ne marche pas non plus:
typeof(MyType).GetInterfaces().Contains(typeof(IMyInterface<>)) /* ALWAYS FALSE */
Cependant, si MyType
implémente IMyInterface<MyType>
cela fonctionne et renvoie true
:
typeof(IMyInterface<MyType>).IsAssignableFrom(typeof(MyType))
Cependant, vous ne connaîtrez probablement pas le paramètre de type T
à l'exécution . Une solution quelque peu hacky est:
typeof(MyType).GetInterfaces()
.Any(x=>x.Name == typeof(IMyInterface<>).Name)
La solution de Jeff est un peu moins compliquée:
typeof(MyType).GetInterfaces()
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IMyInterface<>));
Voici une méthode d'extension sur Type
qui fonctionne dans tous les cas:
public static class TypeExtensions
{
public static bool IsImplementing(this Type type, Type someInterface)
{
return type.GetInterfaces()
.Any(i => i == someInterface
|| i.IsGenericType
&& i.GetGenericTypeDefinition() == someInterface);
}
}
(Notez que ce qui précède utilise linq, ce qui est probablement plus lent qu'une boucle.)
Vous pouvez alors faire:
typeof(MyType).IsImplementing(IMyInterface<>)
Si vous avez un type ou une instance, vous pouvez facilement vérifier s’ils prennent en charge une interface spécifique.
Pour tester si un objet implémente une certaine interface:
if(myObject is IMyInterface) {
// object myObject implements IMyInterface
}
Pour tester si un type implémente une certaine interface:
if(typeof(IMyInterface).IsAssignableFrom(typeof(MyType))) {
// type MyType implements IMyInterface
}
Si vous avez un objet générique et que vous souhaitez effectuer un transtypage ainsi que vérifier si l'interface vers laquelle vous transtz est implémentée, le code est le suivant:
var myCastedObject = myObject as IMyInterface;
if(myCastedObject != null) {
// object myObject implements IMyInterface
}