Исключить типы из IEnumerable с помощью linq - PullRequest
8 голосов
/ 01 февраля 2012

Как я могу отфильтровать объекты по их производному типу с помощью linq-to-objects?

Я ищу решение с лучшей производительностью.

Используемые классы:

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

Мне известны три метода: используйте ключевое слово is, метод Except и метод 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));

Ответы [ 4 ]

9 голосов
/ 01 февраля 2012

Если вы также хотите исключить подклассы Duck, тогда лучше всего использовать is. Вы можете сократить код до .Where(animal => !(animal is Duck));

В противном случае, рекомендация sll о GetType является лучшей

4 голосов
/ 01 февраля 2012
  • Решение, использующее Except(), довольно тяжелое.
  • Имейте в виду, что решение is - вернет true, даже если некоторый класс SomeDuck унаследован от Duck

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

Другое решение может быть:

animals.Where(animal => animal.GetType() != typeof(Duck))
3 голосов
/ 01 февраля 2012

Согласно Разница между OfType <> () и типом проверки в расширении Where () Вызов OfType эквивалентен вашему варианту (a), хотя равно Duck == true , исходя из этого, я бы сказал, придерживайтесь варианта (а).

1 голос
/ 01 февраля 2012

Если вы не хотите, чтобы Duck или какой-либо подкласс Duck были возвращены, вам нужно использовать метод IsAssignableFrom:

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