使用linq从IEnumerable中排除类型

9

如何使用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));

2
如果你有一个继承自DuckMadDuck,那么它应该被返回还是不应该?另外,你想要实现什么目标?使用is和运行时类型检查可能会暴露设计问题。 - vgru
好问题。在这种特定情况下,我希望Duck的子类也被排除在外。这将使我的选项b无效,因为它们比较类型而不是继承关系。 - Myrtle
关于我的第二个问题:从面向对象编程的角度来看,你代码中的其他部分通常不应该关心对象的实际类型。它们应该尽可能地知道“尽可能少”。这就是为什么我想知道你为什么要这样做的原因。 - vgru
1
@Aphelion:真正的问题是,既然你已经拥有了除了“秒表”之外的所有代码,为什么不自己找出性能结果,而要问这个问题呢? - user1228
@Will 已经注意到了,谢谢。现在我有了一份选项清单,秒表确实是下一步要采取的措施。实际上,我已经根据最初问题的答案得到了其他建议,并更新了问题。当时我只有两个建议的选项。我更新了问题以供将来搜索(由其他SO用户)使用,这样他们就可以在一个简单的列表中找到建议和最佳选项。 - Myrtle
显示剩余3条评论
4个回答

9
如果您还想排除鸭子的子类,那么使用is是最好的选择。您可以将代码缩短为.Where(animal => !(animal is Duck)); 否则,sll的建议是使用GetType。

由于我想要排除子类,并且这是一种更短和更易读的表示法,所以我接受了你的答案。 - Myrtle
1
我不相信这会比OfType<Duck>()更好。 - user1228

4
  • Solution using 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();
    
另一种解决方案可以是:
animals.Where(animal => animal.GetType() != typeof(Duck))

1
谢谢!我已经把你的建议包含在问题中了。 - Myrtle

3
根据此链接所述,OfType调用等同于选项(a),尽管有is Duck==true,因此我建议坚持选项(a)。

2

如果你不希望返回Duck 或其任何子类,你需要使用IsAssignableFrom 方法:

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

不错。我以前从未使用过 IsAssignableFrom。我想知道这种方法的性能如何。听起来很适合进行一些分析。 - Myrtle
我期望它的速度与 as 转换和空值检查一样快。 - Louis Kottmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接