如何实现 NotOfType在 LINQ 中有一个很好的调用语法吗?
我正在尝试提出 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我刚刚尝试过这个并且有效...
我错过了什么吗?
I've just tried this and it works...
Am I missing something?
你可能会考虑这个
You might consider this
我不知道你为什么不直接说:
这对我来说似乎完全可读。对我来说,它肯定比
animals.NotOfType()
更直接,如果我遇到它,它会让我感到困惑......第一个永远不会让我困惑,因为它可以立即读取。如果您想要一个流畅的界面,我想您也可以使用
Object
上的扩展方法谓词执行类似的操作:I am not sure why you don't just say:
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
:或者
,您可以将通用参数拆分为两种方法:
此外,您还需要决定是否也排除继承的类型。
How about
Alternatively, you can split the generic parameters across two methods:
Also, you need to decide whether to also exclude inherited types.
这似乎是一个奇怪的建议,但是在普通的旧
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 ofOfType<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 anIEnumerable<T>
, it's trivial to callWhere(x => !(x is T))
; the usefulness of a method likeNotOfType<T>
becomes more questionable in this case.我遇到了类似的问题,在寻找答案时遇到了这个问题。
相反,我选择了以下调用语法:
它的缺点是它枚举了两次集合(因此不能与无限系列或枚举具有不应重复的副作用的集合一起使用),但优点是没有新的需要辅助函数,并且含义很明确。
在我的实际用例中,我最终还在
.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:
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)如果你要制定一种推理方法,你想一路推理。 的示例:
这需要每种类型
If you're going to make a method for inference, you want to infer all the way. That requires an example of each type:
called by