2009-10-28 11 views
9

Tengo un tipo y una interfaz y necesito verificar que el tipo implemente la interfaz de manera abstracta.¿Cómo comprobar si un tipo .NET implementa cierta interfaz .NET de forma abstracta?

He configurado para escribir un código de fuerza bruta usando Reflection y es bastante feo.

Me pregunto si hay una forma mejor que la implementación de la fuerza bruta que estoy haciendo ahora.

¿Alguna idea?

Gracias.

EDITAR

no ha comprobado la aplicación todavía, pero la fuerza de tiro código bruta se parece a esto:

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; 
    } 

Sin compilación ya veo un problema con propiedades, que el código tiene para verificar si la interfaz define getter y/o setter y verificar el (los) método (s) correcto (s), en lugar de asumir ciegamente el getter. De todos modos, como se puede ver, el código es bastante aburrido. Me pregunto si hay una manera mejor ...

EDITAR 2

  • que deseo destacar, que esto es sólo un proyecto de aplicación, que funciona en los casos simples y se rompe para obtener más complejos, como cuando hay sobrecargas de métodos o renombra el método (no sé VB, así que ni siquiera pensé que fuera posible). Pero enfatiza mi punto de que requiere mucho trabajo para hacerlo bien.
  • ¿Por qué querría tal cosa? Necesitamos crear tipos dinámicamente usando Reflection.Emit basado en ciertos metadatos adquiridos dinámicamente. El tipo dinámico generado implementa cierta interfaz, digamos IDynamicObject, y puede derivar de algún tipo de ancestro. Ese tipo de antepasado está compilado estáticamente. Hasta hace poco, el tipo ancestro no tenía permitido implementar la interfaz IDynamicObject. Dado un ejemplo del tipo dinámico, uno tenía que lanzarlo explícitamente a IDynamicObject para obtener acceso a sus métodos (recuerde que el tipo dinámico generado implementa la interfaz). Me gustaría eliminar estos moldes explícitos. La única forma de hacerlo es dejar que el tipo ancestro implemente la interfaz IDynamicObject. Sin embargo, la implementación debe ser todo abstracta, que se verifica mediante el código de creación de tipo dinámico. Voila.
+0

"código de fuerza bruta usando Reflection" - ¿puedes publicarlo? –

+0

¿Qué quieres decir exactamente cuando dices "el tipo implementa la interfaz de manera abstracta"? – LBushkin

+0

OK, unos minutos para asegurarse de que funciona en absoluto. – mark

Respuesta

27

Puede determinar si un tipo implementa una interfaz en particular mediante el uso de Type.IsAssignableFrom:

typeof(MyInterface).IsAssignableFrom(abstractType); 

Editar: después de la clarificación se añadió a la respuesta - para determinar si todas las implementaciones de una interfaz son abstractos de una clase dada, se puede hacer mucho más fácilmente por conseguir un InterfaceMap para el tipo en cuestión:

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

O tal vez un método de extensión genérico ...La respuesta de

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

Se sabe que el tipo implementa la interfaz. Lo que necesito es si la implementación es todo abstracta. – mark

+0

@Mark no hay forma de saber sin reflejar cada miembro para ver si es abstracto. –

+0

Sospecho que. Pero puede haber trucos relacionados con la reflexión de los que no tengo conocimiento. – mark

1

Rex M es correcto en general, pero si su tipo es un parámetro de tipo, también se puede hacer:

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

Se sabe que el tipo implementa la interfaz. Lo que necesito es si la implementación es todo abstracta. – mark

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

Esto solo determina si la clase es abstracta, no si ciertos métodos son abstractos. –

0

no puede utilizar los nombres de los miembros. PORQUE no hay ninguna razón para suponer que el nombre de un miembro le dice algo sobre el miembro de la interfaz que implementa. Reflection le proporciona los medios para ver qué método implementa cuál de la interfaz, sin embargo.

Aquí hay un fragmento que devolvería todo el método en un tipo determinado que se implementa de forma abstracta.

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(); 
} 
Cuestiones relacionadas