2012-02-01 2 views
8

Come posso filtrare gli oggetti in base al loro tipo derivato con linq-to-objects?Escludi tipi modulo IEnumerable con linq

Sto cercando la soluzione con le migliori prestazioni.

Le classi utilizzate:

abstract class Animal { } 
class Dog : Animal { } 
class Cat : Animal { } 
class Duck : Animal { } 
class MadDuck : Duck { } 

so di tre metodi: Utilizzare la parola chiave is, utilizzare il metodo Except, e di utilizzare il metodo OfType.

List<Animal> animals = new List<Animal> 
{ 
    new Cat(), 
    new Dog(), 
    new Duck(), 
    new MadDuck(), 
}; 

// Get all animals except ducks (and or their derived types) 
var a = animals.Where(animal => (animal is Duck == false)); 
var b = animals.Except((IEnumerable<Animal>)animals.OfType<Duck>()); 

// Other suggestions 
var c = animals.Where(animal => animal.GetType() != typeof(Duck)) 

// Accepted solution 
var d = animals.Where(animal => !(animal is Duck)); 
+2

Cosa succede se si dispone di un 'MadDuck', che eredita da un' Anatra'? Dovrebbe essere restituito o no? E, btw, cosa stai cercando di ottenere? L'uso di 'is' e il controllo del tipo di runtime potrebbe indicare problemi di progettazione. – Groo

+0

Buona domanda. In questo caso specifico vorrei che anche le sottoclassi di Duck fossero escluse. Ciò renderebbe la mia opzione 'b' non valida quando confrontano il tipo ma non l'ereditarietà. – Aphelion

+0

Per quanto riguarda la mia seconda ricerca: da un punto di vista OOP, altre parti del codice non dovrebbero di solito riguardare i tipi reali di oggetti. Il dovrebbe sapere "il meno possibile". Ecco perché mi chiedo perché lo stai facendo. – Groo

risposta

9

Se si desidera escludere anche sottoclassi di Duck, quindi il is è il migliore. È possibile abbreviare il codice a poco .Where(animal => !(animal is Duck));

In caso contrario, la raccomandazione del SLL di GetType è meglio

+0

Siccome voglio escludere le sottoclassi e questa è una notazione più breve e più leggibile, ho accettato la tua risposta. – Aphelion

+0

Non credo in questo battito OfType (). – Will

4
  • soluzione utilizzando Except() è abbastanza pesante.
  • Tenete a mente che la soluzione is - restituirebbe vero anche qualche SomeDuck classe ereditata da Duck

    class SomeDuck : Duck 
    ... 
    // duck is Duck == true 
    var duck = new SomeDuck(); 
    

Un'altra soluzione potrebbe essere:

animals.Where(animal => animal.GetType() != typeof(Duck)) 
+1

Grazie. Ho incluso il tuo suggerimento nella domanda. – Aphelion

1

Se non si desidera Duck né alcuna sottoclasse di Duck da restituire, è necessario utilizzare il metodo IsAssignableFrom:

animals.Where(animal => !animal.GetType().IsAssignableFrom(typeof(Duck))); 
+0

Bello. Non ho mai usato 'IsAssignableFrom' prima. Mi chiedo che la performance sia per questo metodo. Sembra un buon caso per alcuni profili. – Aphelion

+0

Mi aspetterei che sia veloce come un cast 'come' poi un controllo nullo. –