2012-04-27 13 views
11

Ci sono tonnellate di domande su questo argomento, ma ne ho una versione leggermente modificata.Determina se una classe implementa un'interfaccia molto specifica

Abbiamo il seguente codice:

interface IFoo { } 
interface IBar : IFoo { } 
class Foo : IFoo { } 
class Bar : IBar { } 

bool Implements_IFoo(Type type) { /* ??? */ } 

Ora, la torsione della storia: il metodo Implements_IFoo deve solo restituire true quando il tipo IFoo implementa solo e non una qualsiasi delle interfacce derivate da IFoo. Per illustrare ecco alcuni esempi di questo metodo:

Implements_IFoo(typeof(Foo)); // Should return true 

Implements_IFoo(typeof(Bar)); // Should return false as Bar type 
           // implements an interface derived from IFoo 

noti che ci possono essere numerose interfacce derivate da IFoo e non necessariamente conoscere la loro esistenza.

Il metodo ovvio è trovare tutte le interfacce derivate da IFoo tramite reflection e quindi controllare solo il tipoof (Bar) .GetInterfaces() è uno di quelli che sono presenti lì. Ma mi stavo chiedendo se qualcuno può trovare una soluzione più elegante.

PS La domanda proviene da un codice che ho trovato che utilizza questo controllo sulle classi (if(obj.GetType() == typeof(BaseClass)) { ... }). Stiamo sostituendo le classi con le interfacce ora quel particolare codice. Inoltre, nel caso in cui - sto implementando questo controllo come una bandiera booleana, quindi questa domanda è puramente ipotetica.

+1

Sono davvero curioso di sapere perché è necessario questo tipo di introspezione in primo luogo. È probabile che il tuo progetto sia sbagliato. – tdammers

+0

Si prega di leggere la domanda 'fino alla fine prima di commentare la prossima volta - Ho già spiegato che questa è una domanda ipotetica;) – Jefim

risposta

9

ho avuto una prova perché sembrava divertente, e questo funziona per il tuo esempio:

bool ImplementsIFooDirectly(Type t) { 
    if (t.BaseType != null && ImplementsIFooDirectly(t.BaseType)) { 
     return false; 
    } 
    foreach (var intf in t.GetInterfaces()) { 
     if (ImplementsIFooDirectly(intf)) { 
      return false; 
     } 
    } 
    return t.GetInterfaces().Any(i => i == typeof(IFoo)); 
} 

risultati:

ImplementsIFooDirectly(typeof(IFoo)); // false 
ImplementsIFooDirectly(typeof(Bar)); // false 
ImplementsIFooDirectly(typeof(Foo)); // true 
ImplementsIFooDirectly(typeof(IBar)); // true 

Non sembra per tutte le interfacce derivate da IFoo, passa semplicemente alla catena di implementazione dell'ereditarietà/interfaccia e verifica se IFoo è presente a qualsiasi livello diverso dal livello esatto del tipo.

Rileva anche se l'interfaccia è ereditata tramite il tipo di base. Non sono sicuro se questo è quello che vuoi.

Ancora, come altri hanno già detto, se questo è davvero un requisito per te, allora potresti avere un problema con il tuo progetto. (EDIT: appena notato la tua domanda è puramente ipotetica allora va bene, naturalmente :).)

+0

Grazie, è esattamente ciò che intendevo. Contrassegnare la risposta come corretta poiché era la prima corretta. :) – Jefim

0

Hai provato a utilizzare la parola chiave is?

BTW in generale, se si dispone di un caso logico in cui alcune classi devono essere di tipo di una classe base ma non uno degli ereditari, è probabilmente la progettazione OO sbagliata, quella che potrebbe violare lo Liskov substitution principle.

+1

Su un oggetto 'Tipo'? – mellamokb

+0

Ancora, 'is' non sta aiutando, poiché restituirà' true' per expr. 'Bar is IFoo' (e l'output desiderato è' false' mentre Bar implementa IFoo 'attraverso' IBar). E se ti interessa leggere attentamente la domanda, non dovrai preoccuparti di menzionare il design di Liskov e OO. Parola chiave: ipotetico/teorico. ;) – Jefim

3

Vedere il seguente sito per esempi su come questo può essere implementato;

C# is keyword usage

In sostanza è possibile utilizzare la 'è' parola chiave per determinare se l'oggetto abita un tipo di classe come parte di essa la pila di ereditarietà di classe.

class Director : Owner { } 
class Developer : Employee { } 
.. 
var dave = new Developer(); 
var steve = new Director(); 
var isEmployee = dave is Employee; // true 
var isAlsoEmploye = steve is Employee; // false 

In linea con la funzione esempio:

bool Implements_Type(object instance, Type type) { 
return instance is type; 
} 
+0

Conosco la parola chiave 'is' e non risolve il problema. Si prega di vedere la parte della mia domanda con gli esempi. Nota che IBar è derivato da IFoo. Così Bar lo implementa anche attraverso IBar. 'is' restituirà true per expr. 'Bar is IFoo' ma questo non è il risultato desiderato. – Jefim

0

La classe tipo ha un metodo chiamato GetInterface è possibile utilizzare.

bool Implements_IFoo(Type t) 
    { 
     return t.GetInterface(typeof(IFoo).Name) != null; 
    } 
+0

Che controlla tutte le interfacce nell'intera gerarchia e quindi fallisce il secondo caso d'uso 'Implements_IFoo (typeof (Bar));' – mellamokb

2
static bool Implements_IFoo(Type type) 
{ 
    if (typeof(IFoo).IsAssignableFrom(type.BaseType)) 
    return false; 

    var barInterfaces = type.GetInterfaces() 
    .Where(iface => typeof(IFoo).IsAssignableFrom(iface)) 
    .ToArray(); 

    return barInterfaces.Length > 0 
    && barInterfaces.Length == barInterfaces.Count(iface => iface == typeof(IFoo)); 
} 
static bool Implements_IFoo_Optimized(Type type) 
{ 
    if (typeof(IFoo).IsAssignableFrom(type.BaseType)) 
    return false; 

    return type.GetInterfaces() 
    .Where(iface => typeof(IFoo).IsAssignableFrom(iface)) 
    .Count() == 1; 
} 
+0

Grazie per la risposta! Questo è esattamente ciò che intendevo. – Jefim

1

Questo dovrebbe fare il trucco:

public bool ImplementsIFooOnly(Type type) 
{ 
    return !type.GetInterfaces().Any(t => 
       { 
        return t is IFoo && !t.Equals(typeof(IFoo)); 
       }); 
} 

Probabilmente ci sono modi più efficienti.

+0

Immagino tu intendessi 'typeof (IFoo) .IsAssignableFrom (t)' invece di 't è IFoo', ma sì, questa è la roba :) – Jefim

+0

E per ogni evenienza - quel codice non controlla le classi di base (beh, quello non era chiaramente definito nella mia domanda) e la condizione in cui un tipo non ha alcuna interfaccia (=> '.Any (..)' restituisce false quindi). – Jefim

Problemi correlati