LINQ:不是任何与全部不
我经常想检查提供的值是否与列表中的一个匹配(例如,在验证时):
if (!acceptedValues.Any(v => v == someValue))
{
// exception logic
}
最近,我注意到 ReSharper 要求我将这些查询简化为:
if (acceptedValues.All(v => v != someValue))
{
// exception logic
}
显然,这在逻辑上是相同的,也许更具可读性(如果您'我做了很多数学工作),我的问题是:这会导致性能下降吗?
感觉应该如此(即 .Any()
听起来像是短路,而 .All()
听起来好像没有),但我没有什么可以证实的这。有谁对查询是否会解决相同的问题有更深入的了解,或者 ReSharper 是否让我误入歧途?
Often I want to check if a provided value matches one in a list (e.g. when validating):
if (!acceptedValues.Any(v => v == someValue))
{
// exception logic
}
Recently, I've noticed ReSharper asking me to simplify these queries to:
if (acceptedValues.All(v => v != someValue))
{
// exception logic
}
Obviously, this is logically identical, perhaps slightly more readable (if you've done a lot of mathematics), my question is: does this result in a performance hit?
It feels like it should (i.e. .Any()
sounds like it short-circuits, whereas .All()
sounds like it does not), but I have nothing to substantiate this. Does anyone have deeper knowledge as to whether the queries will resolve the same, or whether ReSharper is leading me astray?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
根据 ILSpy 实现
All
(就像我实际上去查看了一样,而不是“嗯,该方法的工作原理有点像......”如果我们讨论的是理论而不是实际情况,我可能会这样做影响)。根据 ILSpy 实现
Any
:当然,生成的 IL 可能存在一些细微的差异。但不,不,没有。 IL 几乎是相同的,但在谓词匹配时返回 true 与在谓词不匹配时返回 false 之间存在明显的反转。
当然,这只是 linq-for-objects。某些其他 linq 提供程序可能会比另一个提供程序更好地对待其中一个,但如果是这种情况,则哪个提供程序获得更优化的实现几乎是随机的。
看起来这条规则只是因为有人觉得
if(defineSomethingTrue)
比if(!defineSomethingFalse)
更简单、更易读。公平地说,我认为他们有一点道理,因为我经常发现if(!someTest)
令人困惑*,当存在同等冗长和复杂性的替代测试时,该测试将为条件返回 true我们希望采取行动。但实际上,我个人认为您提供的两种选择中没有什么比另一种更有利的,并且如果谓词更复杂,也许会稍微倾向于前者。*不是令人困惑,因为我不明白,而是令人困惑,因为我担心这个决定有一些我不理解的微妙原因,并且需要一些精神跳跃才能意识到“不,他们只是决定这样做”就这样,等等,我又在看这段代码做什么?...”
Implementation of
All
according to ILSpy (as in I actually went and looked, rather than the "well, that method works a bit like ..." I might do if we were discussing the theory rather than the impact).Implementation of
Any
according to ILSpy:Of course, there could be some subtle difference in the IL produced. But no, no there isn't. The IL is pretty much the same but for the obvious inversion of returning true on predicate match versus returning false on predicate mismatch.
This is linq-for-objects only of course. It's possible that some other linq provider treats one much better than the other, but then if that was the case, it's pretty much random which one got the more optimal implementation.
It would seem that the rule comes down solely to someone feeling that
if(determineSomethingTrue)
is simpler and more readable thanif(!determineSomethingFalse)
. And in fairness, I think they've a bit of a point in that I often findif(!someTest)
confusing* when there's an alternative test of equal verbosity and complexity that would return true for the condition we want to act upon. Yet really, I personally find nothing to favour one over the other of the two alternatives you give, and would perhaps lean very slightly toward the former if the predicate were more complicated.*Not confusing as in I don't understand, but confusing as in I worry that there's some subtle reason for the decision that I don't understand, and it takes a few mental skips to realise that "no, they just decided to do it that way, wait what was I looking at this bit of code for again?..."
您可能会发现这些扩展方法使您的代码更具可读性:
而不是原来的
现在您可以说
You might find these extension methods make your code more readable:
Now instead of your original
you could say
两者将具有相同的性能,因为两者在确定结果后都停止枚举 - 在传递谓词的第一个项目上的
Any()
计算结果为true
和All()
在第一个项目上,谓词计算结果为false
。Both would have identical performance because both stop enumeration after the outcome can be determined -
Any()
on the first item the passed predicate evaluates totrue
andAll()
on the first item the predicate evaluates tofalse
.All
在第一次不匹配时发生短路,所以这不是问题。一个微妙的地方是这
是真的。序列中的所有项目都是偶数。
有关此方法的详细信息,请参阅 Enumerable.All 的文档。
All
short circuits on the first non-match, so it's not a problem.One area of subtlety is that
Is true. All of the items in the sequence are even.
For more on this method, consult the documentation for Enumerable.All.
正如其他答案已经很好地涵盖的那样:这与性能无关,而是与清晰度有关。
您的两种选择都得到了广泛的支持:
但我认为这可能会获得更广泛的支持:
在否定任何内容之前简单地计算布尔值(并命名它)可以在我的脑海中清除很多东西。
As other answers have well covered: this is not about performance, it's about clarity.
There's wide support for both of your options:
But I think this might achieve broader support:
Simply computing the boolean (and naming it) before negating anything clears this up a lot in my mind.
如果您查看 Enumerable 源,您会发现将看到
Any
和All
的实现非常接近:一种方法不可能比另一种方法明显快,因为唯一的区别在于布尔否定,所以更喜欢可读性胜过虚假性能。
If you take a look at the Enumerable source you'll see that the implementation of
Any
andAll
is quite close:There is no way that one method be significantly faster than the other since the only difference lies in a boolean negation, so prefer readability over false performance win.
All()
确定序列中的所有元素是否满足条件。Any()
确定序列中的任何元素是否满足条件。All()
determines whether all elements of a sequence satisfy a condition.Any()
determines whether any element of a sequence satisfies the condition.根据此链接< /a>
According to this link