2014-04-25 6 views
6

Sto cercando di scrivere un metodo di estensione che controlla se un oggetto è sub classe di T.metodo di estensione per verificare se un oggetto è sub classe di T

Ecco quello che ho fatto, ma non accettato da Visual Studio .

public static bool IsChildOf<T>(this object obj) 
{ 
    return (typeof(obj).IsSubclassOf(typeof(T))); 
} 

[Test()] 
public void IsChildOfTest() 
{ 
    var dog = new Dog(); 
    var isAnimal = dog.IsChildOf<Animal>(); 
    Assert.That(isAnimal); 
} 

Qualche idea, come posso scrivere questo?

+1

nota a margine: e termini "di classe bambino", "classe padre" sono scoraggiati Dovresti invece dire "derivato da". Una macchina non è figlia di un veicolo; un'auto deriva da un veicolo. In alternativa, chiamerei il tuo metodo "DerivesFrom ". – dcastro

+0

Sono d'accordo. Riservare i termini figlio/genitore per le relazioni "ha un" piuttosto che "è un". In particolare nelle liste o nelle relazioni ricorsive come gli alberi. – weston

+0

Commenti: 'typeof (X)' richiede che 'X' sia un tipo (come il tuo' T'), non un valore o un'espressione (come il tuo 'obj'). Sei consapevole che 'IsSubclassOf' è falso se uno dei tipi è un'interfaccia o un tipo di valore e se le due classi sono identiche? Forse volevi 'IsAssignableFrom'? Probabilmente è più facile, però, usare la parola chiave C# 'is'. Vedi la risposta di Weston. –

risposta

6

Si può semplicemente utilizzare is. Ma nota che is non corrisponde esattamente a IsSubclassOf. Vedi l'eccellente commento di Jeppe per i dettagli e ho anche un esempio qui sotto.

In una nota a margine, non credo che Java permetta l'equivalente instanceof in un caso così generico per qualche motivo, ma va bene in C#. Cioè .:

public static bool IsChildOf<T>(this object obj) 
{ 
    return obj is T; 
} 

Allora questo lo rende così banale che è più fonte di confusione per i lettori di utilizzare un metodo di estensione di is direttamente. Se è stato utilizzato direttamente il test sarebbe quindi simile:

[Test()] 
public void IsChildOfTest() 
{ 
    var dog = new Dog(); 
    var isAnimal = dog is Animal; 
    Assert.That(isAnimal); 
} 

Un esempio di una delle differenze tra is e IsSubclassOf:

[Test] 
public void IsChildOfTest() 
{ 
    var dog = new Dog(); 
    Assert.False(dog.GetType().IsSubclassOf(typeof(Dog))); 
    Assert.True(dog is Dog); 
} 
+3

Suvviato per aver menzionato 'is'. Non è esattamente equivalente a 'Type.IsSubclassOf'. Alcune differenze: Se 'T' è la * stessa * classe del tipo run-time di' obj', 'is' dice' true' e 'IsSubclassOf' dice' false'. Se 'T' è un'interfaccia,' is' controlla se 'obj' rappresenta quella' interface' mentre 'IsSubclassOf' dice semplicemente' false'. Se il tipo di esecuzione di 'obj' è un tipo di valore (in scatola),' is' controlla come previsto mentre 'IsSubclassOf' dice semplicemente no. 'is' considera anche la co- e controvarianza nei generici, per esempio qualcosa che è' IEnumerable 'è anche' IEnumerable '(vedere' IEnumerable '). –

+0

@Jeppe Stig Nielsen, ottimo punto che non è equivalente. Buono a chiarire questo in caso di equivoci. E infatti, nonostante il nome proposto IsChildOf, l'OP potrebbe non intendere queste distinzioni. –

+0

@JeppeStigNielsen Grazie, ci sono molte informazioni importanti che ho perso!Suppongo che 'is' sia equivalente a' Type.IsAssignableFrom' – weston

6

Uso GetType invece di typeof quando si dispone di un'istanza del tipo:

public static bool IsChildOf<T>(this object obj) 
{ 
    return (obj.GetType().IsSubclassOf(typeof(T))); 
} 
5
public static Boolean IsChildOf<T>(this Object obj) 
{ 
    // Don't forget to handle obj == null. 
    return obj.GetType().IsSubclassOf(typeof(T)); 
} 
+0

L'espressione semplice 'obj is T' non esplode se' obj' è 'null' (si limita a' false'). Vedi altri vantaggi di 'is' nel mio commento alla risposta di Weston. –

2
public static bool IsChildOf<T>(this object obj) 
    { 
     return obj != null && (obj.GetType().IsSubclassOf(typeof(T))); 
    } 

utilizzare anche Assert.IsTrue al posto di Assert.That