如何实现 NotOfType在 LINQ 中有一个很好的调用语法吗?

发布于 2024-10-09 15:49:56 字数 1612 浏览 5 评论 0原文

我正在尝试提出 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<Animal> animals = new Animal[] { monkey, giraffe, lion };

IEnumerable<Animal> fewerAnimals = animals.NotOfType<Giraffe>();

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

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

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));
    }
}

调用这些方法将如下所示:

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

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

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

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

或者我只是在愚蠢?

I'm trying to come up with an implementation for NotOfType, which has a readable call syntax. NotOfType should be the complement to OfType<T> and would consequently yield all elements that are not of type T

My goal was to implement a method which would be called just like OfType<T>, like in the last line of this snippet:

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>();

However, I can not come up with an implementation that supports that specific calling syntax.

This is what I've tried so far:

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));
    }
}

Calling these methods would look like this:

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

and

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

I think that there are major drawbacks with the style of both of these calls. The first one suffers from a redundant "of type/type of" construct, and the second one just doesn't make sense (do I want a list of animals that are neither Animals nor Giraffes?).

So, is there a way to accomplish what I want? If not, could it be possible in future versions of the language? (I'm thinking that maybe one day we will have named type arguments, or that we only need to explicitly supply type arguments that can't be inferred?)

Or am I just being silly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

_失温 2024-10-16 15:49:57

我刚刚尝试过这个并且有效...

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

我错过了什么吗?

I've just tried this and it works...

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

Am I missing something?

几度春秋 2024-10-16 15:49:57

你可能会考虑这个

public static IEnumerable NotOfType<TResult>(this IEnumerable source)
{
    Type type = typeof(Type);

    foreach (var item in source)
    {
       if (type != item.GetType())
        {
            yield return item;
        }
    }
}

You might consider this

public static IEnumerable NotOfType<TResult>(this IEnumerable source)
{
    Type type = typeof(Type);

    foreach (var item in source)
    {
       if (type != item.GetType())
        {
            yield return item;
        }
    }
}
睫毛溺水了 2024-10-16 15:49:56

我不知道你为什么不直接说:

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

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

如果您想要一个流畅的界面,我想您也可以使用 Object 上的扩展方法谓词执行类似的操作:

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

I am not sure why you don't just say:

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

This seems perfectly readable to me. It is certainly more straight-forward to me than animals.NotOfType<Animal, Giraffe>() which would confuse me if I came across it... the first would never confuse me since it is immediately readable.

If you wanted a fluent interface, I suppose you could also do something like this with an extension method predicate on Object:

animals.Where(x => x.NotOfType<Giraffe>())
爱人如己 2024-10-16 15:49:56

或者

animals.NotOf(typeof(Giraffe));

您可以将通用参数拆分为两种方法

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

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

public class NotOfHolder<TSource> : IHideObjectMembers {
    public IEnumerable<TSource> NotOf<TNot>();
}

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

How about

animals.NotOf(typeof(Giraffe));

Alternatively, you can split the generic parameters across two methods:

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

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

public class NotOfHolder<TSource> : IHideObjectMembers {
    public IEnumerable<TSource> NotOf<TNot>();
}

Also, you need to decide whether to also exclude inherited types.

翻身的咸鱼 2024-10-16 15:49:56

这似乎是一个奇怪的建议,但是在普通的旧 IEnumerable 上使用扩展方法怎么样?这将镜像 OfType 的签名,并且还将消除冗余 类型参数的问题。

我还认为,如果您已经有一个强类型序列,则几乎没有理由使用特殊的 NotOfType 方法;从任意类型序列中排除特定类型似乎更有用(在我看来)......或者让我这样说:如果您正在处理IEnumerable,调用 Where(x => !(x is T)); 很简单;在这种情况下,像 NotOfType 这样的方法的有用性变得更加值得怀疑。

This might seem like a strange suggestion, but what about an extension method on plain old IEnumerable? This would mirror the signature of OfType<T>, and it would also eliminate the issue of the redundant <T, TExclude> type parameters.

I would also argue that if you have a strongly-typed sequence already, there is very little reason for a special NotOfType<T> method; it seems a lot more potentially useful (in my mind) to exclude a specific type from a sequence of arbitrary type... or let me put it this way: if you're dealing with an IEnumerable<T>, it's trivial to call Where(x => !(x is T)); the usefulness of a method like NotOfType<T> becomes more questionable in this case.

断舍离 2024-10-16 15:49:56

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

相反,我选择了以下调用语法:

var fewerAnimals = animals.Except(animals.OfType<Giraffe>());

它的缺点是它枚举了两次集合(因此不能与无限系列或枚举具有不应重复的副作用的集合一起使用),但优点是没有新的需要辅助函数,并且含义很明确。

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

I had a similar problem, and came across this question whilst looking for an answer.

I instead settled for the following calling syntax:

var fewerAnimals = animals.Except(animals.OfType<Giraffe>());

It has the disadvantage that it enumerates the collection twice (so cannot be used with an infinite series or a collection where enumeration has side-effects that should not be repeated), but the advantage that no new helper function is required, and the meaning is clear.

In my actual use case, I also ended up adding a .Where(...) after the .OfType<Giraffe>() (giraffes also included unless they meet a particular exclusion condition that only makes sense for giraffes)

朕就是辣么酷 2024-10-16 15:49:56

如果你要制定一种推理方法,你想一路推理。 的示例:

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

这需要每种类型

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

If you're going to make a method for inference, you want to infer all the way. That requires an example of each type:

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

called by

List<ValueType> items = new List<ValueType>() { 1, 1.0m, 1.0 };
IEnumerable<ValueType> result = items.NotOfSameType(2);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文