Reputation: 5841
How can I filter out objects based on their derived type with linq-to-objects?
I am looking for the solution with the best performance.
The classes used:
abstract class Animal { }
class Dog : Animal { }
class Cat : Animal { }
class Duck : Animal { }
class MadDuck : Duck { }
I know of three methods: Use the is
keyword, use the Except
method, and to use the OfType
method.
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));
Upvotes: 9
Views: 2891
Reputation: 385
According to Difference between OfType<>() and checking type in Where() extension the OfType call is equivalent to your option (a), albeit with is Duck==true, so based on that I would say stick to option (a).
Upvotes: 3
Reputation: 16648
If you don't want Duck
nor any subclass of Duck
to be returned, you need to use the IsAssignableFrom
method:
animals.Where(animal => !animal.GetType().IsAssignableFrom(typeof(Duck)));
Upvotes: 2
Reputation: 29083
If you want to also exclude subclasses of Duck, then the is
is best. You can shorten the code to just .Where(animal => !(animal is Duck));
Otherwise, sll's recommendation of GetType is best
Upvotes: 9
Reputation: 62544
Except()
is quite heavy.Keep in mind that solution is
- would return true even some SomeDuck
class inherited from Duck
class SomeDuck : Duck
...
// duck is Duck == true
var duck = new SomeDuck();
An other solution could be:
animals.Where(animal => animal.GetType() != typeof(Duck))
Upvotes: 4