2009-10-28 3 views
9

J'ai un type et une interface et j'ai besoin de vérifier que le type implémente l'interface de manière abstraite.Comment vérifier si un type .NET implémente abstraitement certaines interfaces .NET?

Je me suis mis à écrire un code de force brute en utilisant Reflection et c'est plutôt moche.

Je me demande s'il existe un meilleur moyen que la mise en œuvre de la force brute que je suis en train de faire.

Des idées?

Merci.

EDIT

ai pas vérifié la mise en œuvre encore, mais le projet de code de la force brute ressemble à ceci:

public static bool IsAbstractInterfaceImplementation(Type someType, Type someInterface) 
    { 
    if (!someInterface.IsAssignableFrom(someType)) 
    { 
     return false; 
    } 

    if (!someType.IsAbstract) 
    { 
     return false; 
    } 

    var m_interfaceMemberNames = someInterface.GetMembers().Select(m => m.Name).ToList(); 
    // Make sure every interface member implementation is abstract. 
    foreach (var typeMember in someType.FindMembers(MemberTypes.Event | MemberTypes.Property | MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance, null, null)) 
    { 
     if (m_interfaceMemberNames.Contains(typeMember.Name)) 
     { 
     MethodInfo method; 
     // Make sure the ancestor member is abstract. 
     switch (typeMember.MemberType) 
     { 
     case MemberTypes.Event: 
      if (!IsAbstractImplementation(((EventInfo)typeMember).GetAddMethod())) 
      { 
      return false; 
      } 
      method = ((EventInfo)typeMember).GetRemoveMethod(); 
      break; 
     case MemberTypes.Property: 
      method = ((PropertyInfo)typeMember).GetGetMethod(); 
     default: 
      method = (MethodInfo)typeMember; 
      break; 
     } 
     if (!IsAbstractImplementation(method)) 
     { 
      return false; 
     } 
     } 
    } 
    return true; 
    } 

    public static bool IsAbstractImplementation(MethodInfo methodInfo) 
    { 
    const MethodAttributes expectedAttributes = 
     MethodAttributes.Abstract | 
     MethodAttributes.Public | 
     MethodAttributes.NewSlot | 
     MethodAttributes.Virtual; 

    return (methodInfo.Attributes & expectedAttributes) == expectedAttributes; 
    } 

Sans compiler je vois déjà un problème avec des propriétés, que le code a pour vérifier si l'interface définit getter et/ou setter et vérifie la bonne méthode (s), au lieu d'assumer aveuglément le getter. Quoi qu'il en soit, comme on peut le voir, le code est plutôt terne. Je me demande s'il y a une meilleure façon ...

EDIT 2

  • Je tiens à souligner que c'est juste une mise en œuvre du projet, il fonctionne pour les cas simples et il est cassé pour plus ceux complexes, comme quand il y a des surcharges de méthodes ou des renames de méthode (je ne connais pas VB, donc je ne pensais même pas que c'était possible). Mais cela souligne le fait que cela demande beaucoup de travail pour bien faire les choses.
  • Pourquoi voudrais-je une telle chose? Nous devons créer des types dynamiquement en utilisant Reflection.Emit en fonction de certaines métadonnées acquises dynamiquement. Le type dynamique généré implémente certaines interfaces, par exemple IDynamicObject, et peut dériver de certains types d'ancêtres. Ce type d'ancêtre est compilé statiquement. Jusqu'à récemment, le type ancêtre n'était pas autorisé à implémenter l'interface IDynamicObject. Étant donné une instance du type dynamique, il fallait explicitement le convertir en IDynamicObject pour accéder à ses méthodes (rappelez-vous que le type dynamique généré implémente l'interface). Je voudrais éliminer ces castes explicites. La seule façon de le faire est de laisser le type ancêtre implémenter l'interface IDynamicObject. Cependant, l'implémentation doit être entièrement abstraite, ce qui est vérifié par le code de création de type dynamique. Voila.
+0

"code de force brute utilisant la réflexion" - pouvez-vous l'afficher? –

+0

que voulez-vous dire exactement quand vous dites que le "type implémente l'interface abstraitement"? – LBushkin

+0

OK, quelques minutes pour s'assurer que cela fonctionne du tout. – mark

Répondre

27

Vous pouvez déterminer si un type implémente une interface particulière en utilisant Type.IsAssignableFrom:

typeof(MyInterface).IsAssignableFrom(abstractType); 

Edit: après clarification a été ajouté à la réponse - pour déterminer si toutes les mises en œuvre d'une interface sont abstraites pour une classe donnée, vous pouvez le faire beaucoup plus facilement en obtenant un InterfaceMap pour le type en question:

bool IsAbstractOfInterface(Type classType, Type interfaceType) 
{ 
    var map = classType.GetInterfaceMap(interfaceType); 
    foreach (var info in map.TargetMethods) 
    { 
     if (!info.IsAbstract) 
     { 
      return false; 
     } 
    } 
    return true; 
} 

Ou peut-être une méthode d'extension générique ...

public static bool IsAbstractOf<TInterface>(this Type type) 
{ 
    var map = type.GetInterfaceMap(typeof(TInterface)); 
    foreach (var info in map.TargetMethods) 
    { 
     if (!info.IsAbstract) 
     { 
      return false; 
     } 
    } 
    return true; 
} 
+0

Il est connu que le type implémente l'interface. Ce dont j'ai besoin, c'est de savoir si la mise en œuvre est entièrement abstraite. – mark

+0

@Mark il n'y a aucun moyen de savoir sans réfléchir sur chaque membre pour voir si c'est abstrait. –

+0

Je le soupçonne. Mais peut-être y at-il des astuces liées à la réflexion dont je ne suis pas conscient. – mark

1

réponse Rex M est correct en général, mais si le type est un paramètre de type, vous pouvez également faire:

class Foo<T> where T : IWhatever { 
    // Do your thing, secure in the knowledge that T implements IWhatever 
} 
+0

Il est connu que le type implémente l'interface. Ce dont j'ai besoin, c'est de savoir si la mise en œuvre est entièrement abstraite. – mark

1
public static bool IsAbstractInterfaceImplementation(Type someType, Type someInterface) 
{ 
    return someType.IsAbstract && someInterface.IsAssignableFrom(someType); 
} 
+0

Ceci détermine seulement si la classe est abstraite, pas si certaines méthodes sont abstraites. –

0

Vous ne pouvez pas utiliser les noms de membres. BE parce qu'il n'y a aucune raison de supposer, que le nom d'un membre vous dit quelque chose sur le membre de l'interface qu'il implémente. Reflection vous fournit des moyens de voir quelle méthode implémente celle de l'interface, cependant.

Voici un extrait qui retournerait toutes les méthodes sur un type donné qui ne sont implémentées que de manière abstraite.

static IEnumerable<MethodInfo> GetAbstractImplementations(this Type implementingType, Type interfaceType) 
{ 
    if(!interfaceType.IsInterface) 
     throw new ArgumentException(interfaceType.FullName + " is not an interface."); 
    if(implementingType.IsInterface) 
     throw new ArgumentException(interfaceType.FullName + " is an interface."); 

    if(!interfaceType.IsAssignableFrom(implementingType)) 
     throw new ArgumentException(implementingType.FullName + " does not implement " + interfaceType.FullName + "."); 

    var mapping = implementingType.GetInterfaceMap(interfaceType); 
    return from m in mapping.TargetMethods  
      where m.IsAbstract 
      select m; 
} 

public static bool IsAbstractInterfaceImplementationOf(this Type implementingType, Type interfaceType) 
{ 
    return implementingType.GetAbstractImplementations(interfaceType).Any(); 
} 
Questions connexes