【问题标题】:Sequence contains no elements序列不包含任何元素
【发布时间】:2015-09-04 17:58:37
【问题描述】:

谁能解释一下为什么以下 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字段以帮助调试代码,当它崩溃时你可以看到该值存在于集合中

PS
问题不是随机变量,我删除了参数并在方法内部创建了一个新的局部随机但问题仍然存在

更新

事实证明,您不需要循环来使其崩溃。 如果您多次运行该程序,您将再次收到错误

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

【问题讨论】:

  • 据我所知,您不能在 lamda 表达式中使用“复杂”方法,只能使用可以转换为语句的东西。 stackoverflow.com/questions/1883920/…
  • @ZivWeissman 您可以调用“复杂”方法 - 该问题是关于具有副作用的方法

标签: c# linq random


【解决方案1】:

这是因为 NewMethod 每次迭代都会调用,并且每次都会生成新的随机数。

但在这段代码中,首先生成数字,然后与数字集合的每个元素进行比较。

int temp=NewMethod(minValue, maxValue, random);
int x = numbers.Where(v => v == temp).First();

【讨论】:

  • 不明白,新生成的号码一直存在于集合中。为什么会崩溃?
  • 这个数字在整个集合中总是存在的,但这个数字不等于测试相等的当前数字。
  • ooo,我明白你的意思了,NewMethod 在里面被调用了很多次,当你说迭代时,我想到了 for 循环
【解决方案2】:

@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 的范围。

【讨论】:

  • @GeorgeVovos 不要难过 - 我必须自己模拟才能看到问题!
猜你喜欢
  • 2015-02-19
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-26
  • 2017-05-27
  • 1970-01-01
相关资源
最近更新 更多