序列不包含任何元素
本文关键字:元素 何元素 包含任 | 更新日期: 2023-09-27 17:57:06
有人可以解释为什么下面的 LINQ 查询会抛出 InvalidOperationException 吗?
(不要说列表没有元素,我要找的值总是存在于集合中)
class Program
{
static int lastNumber;
static void Main()
{
int loopCount = 100; int minValue = 1; int maxValue = 10000;
var numbers = Enumerable.Range(minValue, maxValue).ToList();//or ToArray();
Random random = new Random();
for (int i = 0; i < loopCount; i++)
{
//.First() throws the exception but it is obvious that the value exists in the list
int x = numbers.Where(v => v == NewMethod(minValue, maxValue, random)).First();
}
Console.WriteLine("Finished");
Console.ReadLine();
}
private static int NewMethod(int minValue, int maxValue, Random random)
{
var a1 = random.Next(minValue + 1, maxValue - 1);
lastNumber = a1;
return a1;
}
}
仅当我在我的 lambda 表达式中调用 NewMethod 时,才会出现问题。
如果这样做它有效
int temp=NewMethod(minValue, maxValue, random);
int x = numbers.Where(v => v == temp).First();
我添加了 lastNumber 字段来帮助调试代码,可以看到该值在崩溃时存在于集合中
附言问题不在于随机变量,我删除了参数并在方法内部创建了一个新的局部随机,但问题仍然存在
更新
事实证明,您不需要循环来使其崩溃。如果您多次运行该程序,您将再次收到错误
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
class Program
{
static int lastNumber;
static void Main()
{
int minValue = 1, maxValue = 100000;
var numbers = Enumerable.Range(minValue, maxValue).ToArray();
//Crashes sometimes
int x = numbers.Where(v => v == NewMethod(minValue, maxValue)).First();
Console.WriteLine("Finished");
Console.ReadLine();
}
private static int NewMethod(int minValue, int maxValue)
{
Random random = new Random();
var a1 = random.Next(minValue + 1, maxValue - 1);
lastNumber = a1;
return a1;
}
}
@Oleg是对的,但这就是为什么这是问题所在。
Where
扫描列表,查找与给定条件匹配的元素。 在这种情况下,每个元素的条件都会更改。 如果你把问题变小了,比如说一个包含 5 个元素的数组:
List<Int32> (5 items)
1
2
3
4
5
然后循环查找与某个随机数匹配的值(x 是 Item[i]
,r
是随机数):
Item 1: x = 1, r = 2 // fail
Item 2: x = 2, r = 3 // fail
Item 3: x = 3, r = 2 // fail
Item 4: x = 4, r = 3 // fail
Item 5: x = 5, r = 2 // fail
请注意,没有项目与该特定随机数匹配,因此没有项目符合条件,First
会引发异常!
正如您所发现的,解决方法是在枚举之前生成随机数:
int temp=NewMethod(minValue, maxValue, random); // say 2
Item 1: x = 1, temp = 2 // fail
Item 2: x = 2, temp = 2 // success!
旁注:
在这里使用maxValue
有点误导:
Enumerable.Range(minValue, maxValue)
因为要Enumerable.Range
的第二个参数是结果集合的长度,而不是最大值。 在这种情况下,它有效是因为您从 1 开始,但如果您使用 99 和 100,结果会出乎意料 - 你会得到从 99 到 198 的范围。
这是因为NewMethod在每次迭代时都会调用,并且每次都会生成新的随机数。
但是在此代码中,首先生成数字,然后与数字集合的每个元素进行比较。
int temp=NewMethod(minValue, maxValue, random);
int x = numbers.Where(v => v == temp).First();