2012-02-01 7 views
8

¿Cómo puedo filtrar objetos en función de su tipo derivado con linq-to-objects?Excluir tipos de IEnumerable con linq

Estoy buscando la solución con el mejor rendimiento.

Las clases utilizadas:

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

sé de tres métodos: Usar la palabra clave is, utilice el método Except, y utilizar el método 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

¿Qué pasa si tienes un 'MadDuck', que hereda de un' Duck'? ¿Debería ser devuelto o no? Y, por cierto, ¿qué estás tratando de lograr? El uso de 'is' y la verificación de tipo de tiempo de ejecución pueden indicar problemas de diseño. – Groo

+0

Buena pregunta. En este caso específico, me gustaría que también se excluyan las subclases de Pato. Eso haría inválida mi opción 'b' al comparar el tipo pero no la herencia. – Aphelion

+0

En cuanto a mi segunda pregunta: desde el punto de vista de OOP, otras partes de tu código no deberían preocuparse por los tipos reales de tus objetos. El debería saber "lo menos posible". Es por eso que me pregunto por qué estás haciendo esto. – Groo

Respuesta

9

Si desea excluir también subclases de Duck, entonces el is es el mejor. Puede acortar el código para simplemente .Where(animal => !(animal is Duck));

De lo contrario, la recomendación de SLL de GetType es mejor

+0

Como quiero excluir las subclases y esta es una notación más corta y más legible, he aceptado su respuesta. – Aphelion

+0

No creo que este sea mejor OfType (). – Will

4
  • solución utilizando Except() es bastante pesado.
  • Tenga en cuenta que la solución is - volvería cierto incluso algunos SomeDuck clase heredada de Duck

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

Otra solución podría ser:

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

Gracias. He incluido tu sugerencia en la pregunta. – Aphelion

1

Si no desea Duck ni ninguna subclase de Duck a devolver, es necesario utilizar el método IsAssignableFrom:

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

Agradable. Nunca he usado 'IsAssignableFrom' antes. Me pregunto si el rendimiento es para este método. Suena como un buen caso para algunos perfiles. – Aphelion

+0

Esperaría que fuera tan rápido como un lanzamiento 'as' y luego un cheque nulo. –

Cuestiones relacionadas