如何在LINQ中实现具有良好调用语法的NotOfType ?

我正在尝试为NotOfType提供一个实现,它具有可读的调用语法。 NotOfType应该是NotOfType OfType的补充,因此将产生属于T类型的所有元素

我的目标是实现一个像OfType一样调用的方法,就像在这个片段的最后一行一样:

 public abstract class Animal {} public class Monkey : Animal {} public class Giraffe : Animal {} public class Lion : Animal {} var monkey = new Monkey(); var giraffe = new Giraffe(); var lion = new Lion(); IEnumerable animals = new Animal[] { monkey, giraffe, lion }; IEnumerable fewerAnimals = animals.NotOfType(); 

但是,我无法想出支持该特定调用语法的实现。

这是我到目前为止所尝试的:

 public static class EnumerableExtensions { public static IEnumerable NotOfType(this IEnumerable sequence, Type type) { return sequence.Where(x => x.GetType() != type); } public static IEnumerable NotOfType(this IEnumerable sequence) { return sequence.Where(x => !(x is TExclude)); } } 

调用这些方法看起来像这样:

 // Animal is inferred IEnumerable fewerAnimals = animals.NotOfType(typeof(Giraffe)); 

 // Not all types could be inferred, so I have to state all types explicitly IEnumerable fewerAnimals = animals.NotOfType(); 

我认为这两种调用的风格都存在重大缺陷。 第一个遭受冗余的“类型/类型”构造,第二个没有意义(我想要一个既不是动物也不是长颈鹿的动物列表?)。

那么,有没有办法实现我想要的? 如果没有,是否可以在该语言的未来版本中使用? (我想也许有一天我们会有命名类型参数,或者我们只需要显式提供无法推断的类型参数?)

或者我只是愚蠢?

怎么样

 animals.NotOf(typeof(Giraffe)); 

或者, 您可以跨两种方法拆分通用参数 :

 animals.NotOf().Type(); public static NotOfHolder NotOf(this IEnumerable source); public class NotOfHolder : IHideObjectMembers { public IEnumerable NotOf(); } 

此外,您还需要决定是否也排除inheritance的类型。

我不确定你为什么不说:

 animals.Where(x => !(x is Giraffe)); 

这对我来说似乎完全可读。 这对我来说当然比animals.NotOfType()更直接animals.NotOfType()如果我遇到它会让我感到困惑……第一个永远不会让我困惑,因为它立即可读。

如果你想要一个流畅的界面,我想你也可以用Object上的扩展方法谓词来做这样的事情:

 animals.Where(x => x.NotOfType()) 

这可能看起来像一个奇怪的建议,但是对于普通的旧IEnumerable的扩展方法呢? 这将镜像OfType的签名,并且它还将消除冗余类型参数的问题。

我还认为,如果你已经有一个强类型序列,那么特殊的NotOfType方法就没有什么理由了; 在我看来,从任意类型的序列中排除特定类型似乎更有用(在我看来)…或者让我这样说:如果你正在处理IEnumerable ,那么调用它是微不足道的Where(x => !(x is T)) ; 在这种情况下,像NotOfType这样的方法的有用性变得更有问题。

如果你要制作推理方法,你想要一路推断。 这需要每种类型的示例:

 public static class ExtMethods { public static IEnumerable NotOfType(this IEnumerable source) { return source.Where(t => !(t is U)); } // helper method for type inference by example public static IEnumerable NotOfSameType( this IEnumerable source, U example) { return source.NotOfType(); } } 

叫做

 List items = new List() { 1, 1.0m, 1.0 }; IEnumerable result = items.NotOfSameType(2); 

我刚试过这个,它有效……

 public static IEnumerable NotOfType(this IEnumerable sequence) => sequence.Where(x => !(x is TExclude)); 

我错过了什么吗?

你可能会考虑这个

 public static IEnumerable NotOfType(this IEnumerable source) { Type type = typeof(Type); foreach (var item in source) { if (type != item.GetType()) { yield return item; } } } 

我遇到了类似的问题,并在寻找答案时遇到了这个问题。

我决定使用以下调用语法:

 var fewerAnimals = animals.Except(animals.OfType()); 

它的缺点是它枚举了两次集合(因此不能与无限系列一起使用),但缺点是不需要新的辅助函数,其含义很明显。

在我的实际用例中,我最后还在.OfType()之后添加了一个.Where(...) .OfType() (长颈鹿也包括在内,除非它们符合一个只对长颈鹿有意义的特殊排除条件)