web-dev-qa-db-fra.com

Comment déterminer si un type implémente une interface avec une réflexion C #

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);
516
Yippie-Ki-Yay

Tu as quelques choix à choisir

  1. typeof(IMyInterface).IsAssignableFrom(typeof(MyType))

  2. 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<>))
874
Jeff

Utilisez Type.IsAssignableFrom :

_typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
_
63
Snea
typeof(IMyInterface).IsAssignableFrom(someclass.GetType());

ou

typeof(IMyInterface).IsAssignableFrom(typeof(MyType));
28
ajma
    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).

12
Panos Theof

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.

8
toddmo

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>();
7
Ehouarn Perret

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);
7
Ben Wilde

IsAssignableFrom est maintenant déplacé vers TypeInfo:

typeof(ISMSRequest).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo());
2
codeputer

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
1
EricBDev

Qu'en est-il de

typeof(IWhatever).GetTypeInfo().IsInterface
0
LaWi

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<>)
0
Diego

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
    }
0
user11773533