2009-10-28 11 views
9

Ho un tipo e un'interfaccia e ho bisogno di verificare che il tipo implementa l'interfaccia in modo astratto.Come verificare se un tipo .NET implementa in modo astratto determinate interfacce .NET?

Ho impostato per scrivere un codice forza bruto utilizzando Reflection ed è piuttosto brutto.

Mi chiedo se ci sia un modo migliore rispetto all'implementazione della forza bruta che sto facendo ora.

Qualche idea?

Grazie.

EDIT

non hanno ancora controllato l'attuazione, ma la forza progetto di codice bruta assomiglia a questo:

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

senza compilarlo ho già vedo un problema con proprietà, che il codice ha per verificare se l'interfaccia definisce getter e/o setter e verificare i giusti metodi, invece di assumere ciecamente il getter. Ad ogni modo, come si può vedere, il codice è piuttosto noioso. Mi chiedo se c'è un modo migliore ...

EDIT 2

  • desidero sottolineare, che questo è solo un progetto di implementazione, funziona per i casi semplici e si è rotto per più quelli complessi, come quando ci sono overload di metodi o metodi rinomina (non conosco VB, quindi non pensavo nemmeno fosse possibile). Ma sottolinea il mio punto che richiede molto lavoro per farlo nel modo giusto.
  • Perché dovrei volere una cosa del genere? Abbiamo bisogno di creare tipi dinamicamente usando Reflection.Emit sulla base di determinati metadati acquisiti dinamicamente. Il tipo dinamico generato implementa determinate interfacce, ad esempio IDynamicObject, e potrebbe derivare da un tipo di antenato. Quel tipo di antenato è compilato staticamente. Fino a poco tempo fa, il tipo di antenato non era autorizzato a implementare l'interfaccia IDynamicObject. Data un'istanza del tipo dinamico, è necessario eseguirne il cast esplicito su IDynamicObject per ottenere l'accesso ai suoi metodi (ricorda che il tipo dinamico generato implementa l'interfaccia). Vorrei eliminare questi cast espliciti. L'unico modo per farlo è lasciare che il tipo di antenato implementa l'interfaccia IDynamicObject. Tuttavia, l'implementazione deve essere interamente astratta, che viene verificata dal codice di creazione del tipo dinamico. Ecco.
+0

"codice forza bruta utilizzando Reflection" - puoi postarlo? –

+0

cosa intendi esattamente quando dici "il tipo implementa l'interfaccia in modo astratto"? – LBushkin

+0

OK, alcuni minuti per accertarsi che funzioni. – mark

risposta

27

È possibile determinare se un tipo implementa una particolare interfaccia utilizzando Type.IsAssignableFrom:

typeof(MyInterface).IsAssignableFrom(abstractType); 

Edit: dopo chiarimento è stato aggiunto alla risposta - per determinare se tutte le implementazioni di un'interfaccia sono astratti per una data classe, si può fare molto più facilmente ottenere un InterfaceMap per il tipo in questione:

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 forse un metodo di estensione generico ...La risposta di

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

È noto che il tipo implementa l'interfaccia. Ciò di cui ho bisogno è se l'implementazione è completamente astratta. – mark

+0

@ Mark non c'è modo di sapere senza riflettere ciascun membro per vedere se è astratto. –

+0

Lo sospetto. Ma potrebbero esserci trucchi legati alla riflessione di cui non sono a conoscenza. – mark

1

Rex M è corretto, in generale, ma se il tipo è un parametro di tipo, si può anche fare:

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

È noto che il tipo implementa l'interfaccia. Ciò di cui ho bisogno è se l'implementazione è completamente astratta. – mark

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

Determina solo se la classe è astratta, non se determinati metodi sono astratti. –

0

Non è possibile utilizzare i nomi dei membri. Perché non c'è ragione di supporre che il nome di un membro ti dica qualcosa sul membro dell'interfaccia che implementa. Reflection fornisce i mezzi per vedere quale metodo implementa quale dall'interfaccia, comunque.

Ecco uno snippet che restituisce tutti i metodi su un determinato tipo implementati solo in modo astratto.

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(); 
} 
Problemi correlati