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

Chr*_*tte 23 c# linq type-inference code-readability

我正在尝试提供一个NotOfType具有可读调用语法的实现.NotOfType应该是补充,OfType<T>并因此产生所有类型的元素T

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

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<Animal> animals = new Animal[] { monkey, giraffe, lion };

IEnumerable<Animal> fewerAnimals = animals.NotOfType<Giraffe>();
Run Code Online (Sandbox Code Playgroud)

但是,我无法想出一个支持特定调用语法的实现.

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

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

    public static IEnumerable<T> NotOfType<T, TExclude>(this IEnumerable<T> sequence)
    {
        return sequence.Where(x => !(x is TExclude));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

// Animal is inferred
IEnumerable<Animal> fewerAnimals = animals.NotOfType(typeof(Giraffe));
Run Code Online (Sandbox Code Playgroud)

// Not all types could be inferred, so I have to state all types explicitly
IEnumerable<Animal> fewerAnimals = animals.NotOfType<Animal, Giraffe>();
Run Code Online (Sandbox Code Playgroud)

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

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

或者我只是愚蠢?

Bri*_*sio 28

我不确定你为什么不说:

animals.Where(x => !(x is Giraffe));
Run Code Online (Sandbox Code Playgroud)

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

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

animals.Where(x => x.NotOfType<Giraffe>())
Run Code Online (Sandbox Code Playgroud)


SLa*_*aks 11

怎么样

animals.NotOf(typeof(Giraffe));
Run Code Online (Sandbox Code Playgroud)

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

animals.NotOf().Type<Giraffe>();

public static NotOfHolder<TSource> NotOf<TSource>(this IEnumerable<TSource> source);

public class NotOfHolder<TSource> : IHideObjectMembers {
    public IEnumerable<TSource> NotOf<TNot>();
}
Run Code Online (Sandbox Code Playgroud)

此外,您还需要决定是否也排除继承的类型.


Dan*_*Tao 5

这可能看起来像一个奇怪的建议,但是对于普通老的扩展方法IEnumerable呢?这将反映签名OfType<T>,并且还将消除冗余<T, TExclude>类型参数的问题.

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