gpt4 book ai didi

c# - Enumerable.Single 的错误执行?

转载 作者:太空宇宙 更新时间:2023-11-03 15:55:18 24 4
gpt4 key购买 nike

我通过反射器在 Enumerable.cs 中发现了这个实现。

public static TSource Single<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
//check parameters
TSource local = default(TSource);
long num = 0L;
foreach (TSource local2 in source)
{
if (predicate(local2))
{
local = local2;
num += 1L;
//I think they should do something here like:
//if (num >= 2L) throw Error.MoreThanOneMatch();
//no necessary to continue
}
}
//return different results by num's value
}

我认为如果有超过 2 个项目满足条件,他们应该打破循环,为什么他们总是循环遍历整个集合?以防反射器错误地反汇编 dll,我写了一个简单的测试:

class DataItem
{
private int _num;
public DataItem(int num)
{
_num = num;
}

public int Num
{
get{ Console.WriteLine("getting "+_num); return _num;}
}
}
var source = Enumerable.Range(1,10).Select( x => new DataItem(x));
var result = source.Single(x => x.Num < 5);

对于这个测试用例,我认为它会打印“getting 0, getting 1”然后抛出异常。但事实是,它一直在“得到 0...得到 10”并抛出异常。他们像这样实现这个方法有什么算法上的原因吗?

编辑 你们中的一些人认为这是因为谓词表达式的副作用,经过深思熟虑和一些测试用例后,我得出的结论是方面在这种情况下效果并不重要。如果您不同意此结论,请举例说明。

最佳答案

是的,我确实觉得它有点奇怪,尤其是因为不采用谓词的重载(即只对序列起作用)确实似乎具有快速“优化”。


然而,在 BCL 的辩护中,我会说 Single 抛出的 InvalidOperation 异常是 boneheaded exception通常不应将其用于控制​​流。库没有必要对此类情况进行优化。

使用 Single 的代码,其中零个或多个匹配是完全有效的可能性,例如:

try
{
var item = source.Single(predicate);
DoSomething(item);
}

catch(InvalidOperationException)
{
DoSomethingElseUnexceptional();
}

应该重构为将异常用于控制流的代码,例如(仅示例;这可以更有效地实现):

var firstTwo = source.Where(predicate).Take(2).ToArray();

if(firstTwo.Length == 1)
{
// Note that this won't fail. If it does, this code has a bug.
DoSomething(firstTwo.Single());
}
else
{
DoSomethingElseUnexceptional();
}

换句话说,我们应该将 Single 的使用留给我们期望序列包含一个匹配项的情况。它的行为应该与 First 相同,但带有额外的运行时断言,即序列不包含多个匹配项。与任何其他断言一样,失败,即 Single 抛出的情况,应该用于表示程序中的错误(在运行查询的方法中或传递给的参数中)它由调用者)。

这给我们留下了两种情况:

  1. 断言成立:只有一个匹配项。在这种情况下,我们希望 Single 无论如何 消耗整个序列来声明我们的声明。 “优化”没有任何好处。事实上,有人可能会争辩说,OP 提供的“优化”示例实现实际上会更慢,因为要检查循环的每次迭代。
  2. 断言失败:有零个或多个匹配项。在这种情况下,我们抛出的时间比我们可能的晚,但这没什么大不了的,因为异常是愚蠢的:它表明存在错误必须修复。

总而言之,如果“糟糕的实现”影响了您在生产环境中的性能表现,则:

  1. 您错误地使用了Single
  2. 您的程序中有错误。错误修复后,这个特定的性能问题就会消失。

编辑:澄清了我的观点。

编辑:这是 Single 的有效用法,其中失败表示调用代码中的错误(参数错误):

public static User GetUserById(this IEnumerable<User> users, string id)
{
if(users == null)
throw new ArgumentNullException("users");

// Perfectly fine if documented that a failure in the query
// is treated as an exceptional circumstance. Caller's job
// to guarantee pre-condition.
return users.Single(user => user.Id == id);
}

关于c# - Enumerable.Single 的错误执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23915815/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com